zoukankan      html  css  js  c++  java
  • 洛谷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
    ");
                continue;
            }
            if((n==1)||(m==1))
            {
            	printf("NO
    ");
                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
    ");
            }
            else
            printf("NO
    ");
        }
        return 0;
    } 
    
    
    
  • 相关阅读:
    LOJ P10004 智力大冲浪 题解
    LOJ P10011 愤怒的牛 题解
    LOJ P10002 喷水装置 题解
    洛谷 P2279 [HNOI2003]消防局的设立 题解
    洛谷 P5640 【CSGRound2】逐梦者的初心 题解
    洛谷 P2827 蚯蚓 题解
    [SHOI2012]魔法树
    浅析树链剖分
    [Bzoj1731]排队布局
    [POJ-1201]Intervals
  • 原文地址:https://www.cnblogs.com/ShineEternal/p/10834227.html
Copyright © 2011-2022 走看看