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

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

让你在一个n*m的矩阵中,找出是否能按照约定方案打扫全部指定房间。

首先不难得出一个结论:有奇数个需要打扫的房间时一定无解。

证明?

每一次打扫都要满足条件3和4,而闭合的环线为多边形,显然必须对称(即通过平移可得到矩形),不难看出:每一次都能且只能打扫偶数个房间。

然后稍作分析,发现每个格子的度为2(即进入此房再出去)。

考虑建图。

一个房间上下左右有门,我们自然而然想到一个点向周围四个连边,就构成了黑白染色的模型。

一个矩阵中的房间最多用两条路线打扫即可。

每个点都要走到。
所以每个点都会向上下左右异色格点流出1,同时也会接受另一个点的流入。

我们这时将白点流向黑点的流反向,这样每个白点流入2,每个黑点流出2。

于是每个点有2的流量,来说明可以有两条边和它相连。

黑点都向S连边,白点都向T连边

然后图建好了,开始跑网络流,如果满流就证明所有的点都进,出过一次,打扫完毕,输出yes;否则no

建图总结:

  • 节点含义:房间
  • 边的含义:打扫路线
  • 边如何相连:四连通
  • 源点S:矩阵外一点
  • 汇点T:矩阵外一点

代码:


#include<cstdio>
#include<vector> 
#include<iostream>
#include<queue>
#include<cstring>
using namespace std;
#define inf 0x7fffffff
int n,m,s,t,ans;
int gx[5]={0,0,-1,0,1};
int gy[5]={0,-1,0,1,0};
//int gy[5]={0,-1,1,0,0};
//int gx[5]={0,0,0,-1,1};
int d[1000],id[105][105];
char a[105][105];
struct edge
{
    int to,val,rev;
    edge(int _to,int _val,int _rev)
    {
        to=_to;
        val=_val;
        rev=_rev;
    }
};
vector<edge>e[1000];
void add(int x,int y,int w)
{
    e[x].push_back(edge(y,w,e[y].size()));
    e[y].push_back(edge(x,0,e[x].size()-1));
}
bool bfs()
{
   memset(d,-1,sizeof(d));
    
    queue<int>q;
   
    q.push(s);
    d[s]=0;
    while(!q.empty())
    {
        int x=q.front();
        q.pop();
        for(int i=0;i<e[x].size();i++)
        {
            int y=e[x][i].to;
            if((d[y]==-1)&&e[x][i].val)
            {
            	q.push(y);
                d[y]=d[x]+1;
                
            }
        }
    }
    if(d[t]==-1)
    return 0;
    else
    return 1;
}
int dfs(int x,int low)
{
    if(x==t||low==0)return low;
    int totflow=0;
    for(int i=0;i<e[x].size();i++)
    {
        int y=e[x][i].to;
        int rev=e[x][i].rev;
        if((d[y]==(d[x]+1))&&e[x][i].val)
        {
            int a=dfs(y,min(low,e[x][i].val));
            e[x][i].val-=a;
            e[y][rev].val+=a;
            low-=a;
            totflow+=a;
            if(low==0)return totflow;
        }
    }
    if(low!=0)d[x]=-1;
    return totflow;
}
int main()
{
    int T;
    scanf("%d",&T);
    while(T--)
    {
        for(int i=0;i<=1000;i++)
        e[i].clear();
        int cnt=0,tot=0,sum=0;
        scanf("%d%d",&n,&m);
        for(int i=1;i<=n;i++)
        {
            for(int j=1;j<=m;j++)
            {
                cin>>a[i][j];
                id[i][j]=++cnt;
                if(a[i][j]=='.')tot++;
            }
        }
        s=0;
        t=cnt+1;
        if(tot%2==1)
        {
            printf("NO\n");
            continue;
        }
        if((n==1)||(m==1))
        {
        	printf("NO\n");
            continue;
        }
        for(int i=1;i<=n;i++)
        {
            for(int j=1;j<=m;j++)
            {
                    if(a[i][j]=='.')
                    {
                if(((i+j)%2)==1)
                {
                        add(s,id[i][j],2);
                        sum+=2;
                        for(int k=1;k<=4;k++)
                        {
                            int nx=i+gx[k];
                            int ny=j+gy[k];
                            if((nx>=1)&&(nx<=n)&&(ny>=1)&&(ny<=m)&&(a[nx][ny]!='#'))
                                add(id[i][j],id[nx][ny],1);
                        }
                }
                else
                {
                    add(id[i][j],t,2);
                }
                    }
            }
        }
        ans=0;
        while(bfs())
        {
     
        ans+=dfs(s,inf);
   		}
        if(ans==tot)
        {
            printf("YES\n");
        }
        else
        printf("NO\n");
    }
    return 0;
} 


全部评论

相关推荐

头像
03-03 13:17
已编辑
苏州大学 Java
面试官真的很有耐心,人非常nice,但问得也是真的很细。面完半小后约HR面。有没有人说说HR面会问啥?【希望能过吧,以前真没想到面个试这么耗精力,这一周感觉都被掏空了】1.请做一下自我介绍。2.你掌握的数据结构有哪些?3.请讲一下一致性哈希的原理和解决的问题。4.请讲一下Ring&nbsp;buffer(环形缓冲区)的相关内容。5.请讲解一下HTTP状态码的相关分类和含义(如2xx、3xx、4xx、5xx)。6.请讲解一下四层网络负载均衡和七层网络负载均衡的区别,以及各自的应用场景。7.请讲一下反向代理的原理和常用工具,以及正向代理的相关内容。8.进程间通信的方式有哪些?哪种方式效率更高,为什么?9.请讲一下MySQL主从复制的实现原理(基于binlog、redolog相关)。10.多个从节点之间出现数据不一致的问题该如何解决?11.你了解的消息中间件有哪些?RabbitMQ、RocketMQ、Kafka这三种消息中间件的区别是什么?12.Redis中最常用的数据结构有哪些?13.请讲一下Redis中Zset(sorted&nbsp;set)的底层实现和优化策略。14.什么是小哈希和大哈希,二者在查找、插入性能上有什么区别?15.请讲一下TCC分布式事务算法的相关内容,以及它和2PC、3PC的区别。16.你在项目中使用的服务发现组件是什么,它的实现原理是什么?17.你在项目中使用的序列化协议是什么,为什么选择该协议?18.长连接的适用场景是什么?哪些场景不适合使用长连接,原因是什么?19.请设计一个评论系统(包括数据库表设计、数据结构、关联关系等)。20.【反问】想具体知道会做哪些模块的工作?有没有导师?
百特曼3:节子还是一如既往的八股大厂
查看78道真题和解析
点赞 评论 收藏
分享
评论
点赞
收藏
分享

创作者周榜

更多
牛客网
牛客网在线编程
牛客网题解
牛客企业服务