题目描述

学校新建了一批宿舍,值日生小A要把所有的空房间都打扫一遍。这些宿舍的布局很奇怪,整个建筑物里所有的房间组成一个N * M的矩阵,每个房间的东南西北四面墙上都有一个门通向隔壁房间。另外有些房间是堆放杂物的,无需打扫。小A想设计若干条打扫路线,使得恰好进出每个需打扫的房间各一次,而且进出每个房间不能通过同一个门。要求每条路线都是一个闭合的环线,并且每条路线经过的房间数大于2。

如下面两图所示均为满足要求的打扫方案(灰色格子为放杂物的房间):

小A发现对于某些房间布局是不存在这样的满足要求的方案的。他请你写一个程序计算一下,对于一种给定的房间布局,满足要求的方案是否存在。

输入输出格式

输入格式:

输入文件的第一行是一个整数T (1 ≤ T ≤ 10),表示该文件中一共有T组数据。接下来依次是T组数据的信息。每组数据的第一行包含两个整数N和M,接下来的N行,每行包含M个字符,表示一个房间布局。字符'.'表示该房间需要打扫,'#'表示该房间是堆放杂物的,无需打扫。

输出格式:

共输出T行,对每组数据输出一行,为"YES"或"NO",表示打扫方案存在与否。

输入输出样例

输入样例#1:

3 10 12 4
76 60 87
78 84 84 84 81 82 72 51 77 57
85 84 62 87 88 64 81 90 80 66 88 85
65 83 63 79
2
4 5 1
4 4 2

输出样例#1:

85.64
78.00

说明

对50%的数据,3 ≤ N,M ≤ 12

对100%的数据,3 ≤ N,M ≤ 30

Solution

唔,乍看上去比较像是一个搜索题。。然后可以发现的是网络流黑白染色维护这个题并不是一件很困难的事。因为如果我们能从一个门出去,那么我们反过来走一定可以从同一个门进来。这样我们就可以这么实现,把每个黑格子与源点连流量为2的边,每个白格子与汇点连流量为2的边,黑格子和白格子之间用流量为1表示转移。这样就可以轻松实现这道题。

Code

#pragma comment(linker, "/STACK:1024000000,1024000000")
#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<queue>
#define re register
#define inf 400000000
#define MAXN 10001
#define MAXM 100001
using namespace std;
int n,s,q,dis[2000011],t,l,cur[200051],m,tot,sum;
struct po
{
int nxt,to,w;
}edge[MAXM];
int head[MAXN],dep[MAXN],num=-1;
char a[101][101];
int id[101][101],nm;
int dx[5]={0,1,0,-1,0};
int dy[5]={0,0,1,0,-1};
inline int read()
{
int x=0,c=1;
char ch=' ';
while((ch>'9'||ch<'0')&&ch!='-')ch=getchar();
while(ch=='-')c*=-1,ch=getchar();
while(ch<='9'&&ch>='0')x=x*10+ch-'0',ch=getchar();
return x*c;
}
inline void add_edge(int from,int to,int w)
{
edge[++num].nxt=head[from];
edge[num].to=to;
edge[num].w=w;
head[from]=num;
}
inline void add(int from,int to,int w)
{
add_edge(from,to,w);
add_edge(to,from,0);
}
inline bool bfs()
{
memset(dep,0,sizeof(dep));
queue<int> q;
while(!q.empty())
q.pop();
q.push(s);
dep[s]=1;
while(!q.empty())
{
int u=q.front();
q.pop();
for(re int i=head[u];i!=-1;i=edge[i].nxt)
{
int v=edge[i].to;
if(dep[v]==0&&edge[i].w>0)
{
dep[v]=dep[u]+1;
if(v==t)
return 1;
q.push(v);
}
}
}
return 0;
}
inline int dfs(int u,int dis)
{
if(u==t)
return dis;
int diss=0;
for(re int& i=cur[u];i!=-1;i=edge[i].nxt)
{
int v=edge[i].to;
if(edge[i].w!=0&&dep[v]==dep[u]+1)
{
int check=dfs(v,min(dis,edge[i].w));
if(check>0)
{
dis-=check;
diss+=check;
edge[i].w-=check;
edge[i^1].w+=check;
if(dis==0) break;
}
}
}
return diss;
}
inline int dinic()
{
int ans=0;
while(bfs())
{
for(re int i=0;i<=t;i++)
cur[i]=head[i];
while(int d=dfs(s,inf))
ans+=d;
}
return ans;
}
inline void prepare()
{
memset(head,-1,sizeof(head));
num=-1;nm=0;
sum=0;tot=0;
}
int main()
{
//freopen("date.in","r",stdin);
int T=read();
while(T--){
prepare();
n=read();m=read();
for(re int i=1;i<=n;i++)
for(re int j=1;j<=m;j++){
cin>>a[i][j];
id[i][j]=++nm;
if(a[i][j]!='#') tot++;
}
s=0;t=n*m+1;
if(tot%2==1){cout<<"NO"<<endl;continue;}
for(re int i=1;i<=n;i++)
for(re int j=1;j<=m;j++){
if(i+j&1==1){
if(a[i][j]!='#'){
add(s,id[i][j],2);sum+=2;
for(re int k=1;k<=4;k++){
int lx=i+dx[k],ly=j+dy[k];
if(lx>=1&&lx<=n&&ly>=1&&ly<=m&&a[lx][ly]!='#')
add(id[i][j],id[lx][ly],1);
}
}
}else add(id[i][j],t,2);
}
int d=dinic();
if(d==sum) cout<<"YES"<<endl;
else cout<<"NO"<<endl;
}
return 0;
}

[TJOI2010]打扫房间的更多相关文章

  1. 洛谷P3877 [TJOI2010]打扫房间 解题报告

    首先整理一下条件: 1.恰好进出每个需打扫的房间各一次 2.进出每个房间不能通过同一个门 (其实前两个条件是一回事) 3.要求每条路线都是一个闭合的环线 4.每条路线经过的房间数大于2 让你在一个n* ...

  2. Luogu3877 TJOI2010 打扫房间 二分图、网络流

    传送门 真是菜死了模板题都不会-- 首先\(30 \times 30\)并不能插头DP,但是范围仍然很小所以考虑网络流. 注意每个点都要包含在一个回路中,那么每一个点的度数都必须为\(2\),也就是说 ...

  3. 洛谷$P3877\ [TJOI2010]$打扫房间 网络流

    正解:网络流 解题报告: 传送门$QwQ$ 昂考虑把题目的约束条件详细化?就说每个格点能向四连通连边,问能否做到每个格点度数等于2? $umm$就先黑白染色建两排点呗,然后就$S$向左侧连流量为2的边 ...

  4. P3877 [TJOI2010]打扫房间

    xswl以为是个插头dp,然后发现就是个sb题 相当于就是个匹配.每个格子度数为2,所以可以匹配2个相邻的点.匹配显然的用网络流.最后check有没有不匹配的点即可. #include<bits ...

  5. [ TJOI 2010 ] 打扫房间

    \(\\\) Description 给出一个\(N\times M\) 的网格,一些格子是污点,求是否能用多个封闭的环路覆盖所有不是污点的格点. 封闭的环路覆盖的含义是,每条路径都必须是一个环,且每 ...

  6. 洛咕 P3965 [TJOI2013]循环格

    同tjoi2010 打扫房间,每个点入度,出度都为1,可以向相邻4个点连边,但只有原来存在的边费用为0. // luogu-judger-enable-o2 #include<bits/stdc ...

  7. JVM学习(4)——全面总结Java的GC算法和回收机制

    俗话说,自己写的代码,6个月后也是别人的代码……复习!复习!复习!涉及到的知识点总结如下: 一些JVM的跟踪参数的设置 Java堆的分配参数 -Xmx 和 –Xms 应该保持一个什么关系,可以让系统的 ...

  8. iOS学习19之OC类的扩展

    为一个类扩展功能:1.子类化:2.修改源代码:3.定义协议:4.Category:类目 1.Category 1> Category的作用 Category:也叫分类,类目,是为没有源代码的类扩 ...

  9. uva 107 - The Cat in the Hat

     The Cat in the Hat  Background (An homage to Theodore Seuss Geisel) The Cat in the Hat is a nasty c ...

随机推荐

  1. $().each() 与 $.each()区别,以及 jquery ajax 应用

    在jquery 中我们可以选择$().each() 与 $.each() 进行迭代对象和数组 $(items).each(function(){ //item })   , 而后者则 $.each(i ...

  2. Hadoop格式化HDFS报错java.net.UnknownHostException: centos64

    异常描述 在对HDFS格式化,执行hadoop namenode -format命令时,出现未知的主机名的问题,异常信息如下所示: [shirdrn@localhost bin]$ hadoop na ...

  3. bnuoj 34990(后缀数组 或 hash+二分)

    后缀数组倍增算法超时,听说用3DC可以勉强过,不愿写了,直接用hash+二分求出log(n)的时间查询两个字符串之间的任意两个位置的最长前缀. 我自己在想hash的时候一直在考虑hash成数值时MOD ...

  4. bzoj 1415(概率dp和bfs预处理)

    感觉挺经典的一道题目. 先用 bfs 预处理下一步走到的位置.因为每一步走法都是固定的,所以可以用dp的方法来做. 1415: [Noi2005]聪聪和可可 Time Limit: 10 Sec  M ...

  5. LINQPad_批量修改图片名称

    用到这个工具是在后台批量修改图片名称的时候 下载并安装LINQPad. 这里要注意:在复制path路径的时候C:\xampp\htdocs\day01\angularjs_day01_am\angul ...

  6. cordova添加android平台时选择安装版本: requirements check failed for jdk 1.8

    提示如上: 因为android-24 需要 jdk1.8 ,这里指定 android@5.1.1   即可 android-23,如下图

  7. linux部署项目(Java项目+Tomcat+mysql)

    http://blog.csdn.net/liujiahan629629/article/details/27121739

  8. delphi------项目类型

    Console Application:控制台应用程序 writeln('HelloWorld'); //接收用户输入字符 readln: //直到用户输入回车结束 VCL Forms Applica ...

  9. 《深入理解Linux网络技术内幕》阅读笔记 --- 邻居子系统

    1.封包从L3至L2的传送过程如下所示: 本地主机的路由子系统选择L3目的地址(下一个跃点). 根据路由表,如果下一个跃点在同一个网络中,邻居层就把目的L3地址解析为跃点的L2地址.这个关联会被放入缓 ...

  10. Python列表切片详解([][:][::])

    Python切片是list的一项基本的功能,最近看到了一个程序,里面有这样一句类似的代码: a = list[::10] 1 不太明白两个冒号的意思就上网百度,发现大多数人写的博客中都没有提到这一个用 ...