zoukankan      html  css  js  c++  java
  • 5120: [2017国家集训队测试]无限之环

    5120: [2017国家集训队测试]无限之环

    Time Limit: 20 Sec Memory Limit: 512 MB
    Submit: 128 Solved: 76
    [Submit][Status][Discuss]

    Description

    曾经有一款流行的游戏,叫做InfinityLoop,先来简单的介绍一下这个游戏:
    游戏在一个n×m的网格状棋盘上进行,其中有些小方格中会有水管,水管可能在方格某些方向的边界的中点有接口
    ,所有水管的粗细都相同,所以如果两个相邻方格的公共边界的中点都有接头,那么可以看作这两个接头互相连接
    。水管有以下15种形状:

    游戏开始时,棋盘中水管可能存在漏水的地方。
    形式化地:如果存在某个接头,没有和其它接头相连接,那么它就是一个漏水的地方。
    玩家可以进行一种操作:选定一个含有非直线型水管的方格,将其中的水管绕方格中心顺时针或逆时针旋转90度。
    直线型水管是指左图里中间一行的两种水管。
    现给出一个初始局面,请问最少进行多少次操作可以使棋盘上不存在漏水的地方。

    Input

    第一行两个正整数n,m代表网格的大小。
    接下来n行每行m数,每个数是[0,15]中的一个
    你可以将其看作一个4位的二进制数,从低到高每一位分别代表初始局面中这个格子上、右、下、左方向上是否有水管接头。
    特别地,如果这个数是000,则意味着这个位置没有水管。
    比如3(0011(2))代表上和右有接头,也就是一个L型,而12(1100(2))代表下和左有接头,也就是将L型旋转180度。
    n×m≤2000

    Output

    输出共一行,表示最少操作次数。如果无法达成目标,输出-1

    Sample Input

    2 3

    3 14 12

    3 11 12

    Sample Output

    2

    HINT

    样例1棋盘如下

    旋转方法很显然,先将左上角虚线方格内的水管顺时针转90度

    然后右下角虚线方格内的水管逆时针旋转90度,这样就使得水管封闭了.

    Solution

    我就奇怪有谁能第一眼就觉得这是个费用流。。。。。
    如果没看题解写出来这题那这人网络流真是出神入化。。。。。
    考虑题目要求,每个格子插头都必须和它旁边的格子里的插头对上,形成一个闭合的水管通路。第一感觉,这题很难做啊,你要考虑怎么样才能够形成最短的通路,然后同时还要满足你旋转的次数最小。着实麻烦。。。
    然后我们可以这么考虑,只要一个格子有了一个头,那么它就必须和旁边的一个格子里的头对应起来,否则就不能形成通路。所有格子的任何一个头都满足这个道理。那么我们就需要让他们全部匹配。
    好了,劈配。。。我们是不是可以就这么使用网络流来实现这个题呢?
    考虑简单的版本,假设我当场给你这么些格子,然后你去判断它是不是能够形成通路。。这是一个网络流的经典的黑白染色问题,就不在此累述。
    继续考虑更难一点的,假设我转格子没有花费,给你的图是不是能够形成一个通路。。拆完点继续跑就可以了,明显也没有什么太大的难度。
    我们考虑这道题目,每转动一次需要1的花费,那么我们把网络流更改为费用流即可,因为转动一次的费用都是1 ,所以我们可以较容易的实现。
    接下来就是大问题建模。。
    很明显这个题有三种不同样式的格子,一个是死胡同形,一个是L形,还有一个T形。剩下的两种要么不能动,要么动了和没动一样,不需要讨论。
    对于死胡同形,很明显转到旁边需要1的花费,而转到对面需要2的花费。
    对于L形,不大明显的是我们转动90度就相当于把一条边转到了对面,而180度就是完全旋转过去。。。
    对于T形,可以发现他就是一个反过来的死胡同形,反过来连边就可以了。。
    那么我们直接跑费用流就可以了。代码不是很长。

    #pragma comment(linker, "/STACK:1024000000,1024000000")
    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<cmath>
    #include<algorithm>
    #include<queue>
    #define inf 1000000001
    #define re register
    #define ll long long
    #define min(a,b) a<b?a:b
    #define MAXN 20001
    #define MAXM 40000005
    #define id1 nm[i][j]
    #define id2 (nm[i][j]+(n*m))
    #define id3 (nm[i][j]+(n*m*2))
    #define id4 (nm[i][j]+(n*m*3))
    #define id5 (nm[i][j]+(n*m*4))
    using namespace std;
    int n,m,s,t;
    int head[MAXN],num=-1,tot,dis[MAXN],b[MAXN],maxx;
    int to[100005],nxt[100005],w[100005],edis[100005];
    int a[2001][2001],nm[2001][2001];
    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 too,int ww,ll dis)
    {
        nxt[++num]=head[from];
        to[num]=too;
        w[num]=ww;
        edis[num]=dis;
        head[from]=num;
    }
    inline void add(int from,int too,int ww,ll dis)
    {
        add_edge(from,too,ww,dis);
        add_edge(too,from,0,-dis);
    }
    inline bool spfa()
    {
        for(re int i=s;i<=t;i++) dis[i]=inf+1;
        memset(b,0,sizeof(b));
        deque<int> q;
        q.push_back(t);
        dis[t]=0;
        b[t]=1;
        while(!q.empty()){
            int u=q.front();
            q.pop_front();
            b[u]=0;
            for(re int i=head[u];i!=-1;i=nxt[i]){
                int v=to[i];
                if(w[i^1]>0&&dis[v]>dis[u]-edis[i]){
                    dis[v]=dis[u]-edis[i];
                    if(!b[v]){
                        b[v]=1;
                        if(!q.empty()&&dis[v]<dis[q.front()])
                        q.push_front(v);
                        else
                        q.push_back(v);
                    }
                }
            }
        }
        return dis[s]<inf;
    }
    inline int dfs(int u,int low)
    {
        b[u]=1;
        if(u==t) return low;
        int diss=0;
        for(re int i=head[u];i!=-1;i=nxt[i]){
            int v=to[i];
            if(w[i]&&!b[v]&&dis[v]==dis[u]-edis[i]){
                int check=dfs(v,min(w[i],low));
                if(check){
                    tot+=check*edis[i];
                    low-=check;
                    diss+=check;
                    w[i]-=check;
                    w[i^1]+=check;
                    if(low==0) break;
                }
            }
        }
        return diss;
    }
    inline int max_flow()
    {
        int ans=0;
        while(spfa()){
            b[t]=1;
            while(b[t]){
                memset(b,0,sizeof(b));
                ans+=dfs(s,inf);    
            }
        }
        return ans;
    }
    int main() 
    {
        //freopen("date.in","r",stdin);
        memset(head,-1,sizeof(head));
        n=read();m=read();
        for(re int i=1;i<=n;i++)
        	for(re int j=1;j<=m;j++)
        		a[i][j]=read(),nm[i][j]=(i-1)*m+j;
        s=0;t=5*n*m+1;
        for(re int i=1;i<=n;i++)
        	for(re int j=1;j<=m;j++){
        		if((i+j)%2==0) add(s,nm[i][j],inf,0);
        		else add(nm[i][j],t,inf,0);
        	}
        for(re int i=1;i<=n;i++){
        	for(re int j=1;j<=m;j++)
        	if((i+j)%2==0){
        		if(a[i][j]==1){add(id1,id2,1,0);add(id2,id3,1,1);add(id2,id5,1,1);add(id2,id4,1,2);maxx++;}
        		if(a[i][j]==2){add(id1,id3,1,0);add(id3,id2,1,1);add(id3,id4,1,1);add(id3,id5,1,2);maxx++;}
        		if(a[i][j]==4){add(id1,id4,1,0);add(id4,id3,1,1);add(id4,id5,1,1);add(id4,id2,1,2);maxx++;}
        		if(a[i][j]==8){add(id1,id5,1,0);add(id5,id2,1,1);add(id5,id4,1,1);add(id5,id3,1,2);maxx++;}
        		if(a[i][j]==3){add(id1,id2,1,0);add(id1,id3,1,0);add(id2,id4,1,1);add(id3,id5,1,1);maxx+=2;}
        		if(a[i][j]==6){add(id1,id3,1,0);add(id1,id4,1,0);add(id3,id5,1,1);add(id4,id2,1,1);maxx+=2;}
        		if(a[i][j]==9){add(id1,id5,1,0);add(id1,id2,1,0);add(id5,id3,1,1);add(id2,id4,1,1);maxx+=2;}
        		if(a[i][j]==12){add(id1,id4,1,0);add(id1,id5,1,0);add(id4,id2,1,1);add(id5,id3,1,1);maxx+=2;}
        		if(a[i][j]==7){add(id1,id2,1,0);add(id1,id3,1,0);add(id1,id4,1,0);add(id2,id5,1,1);add(id3,id5,1,2);add(id4,id5,1,1);maxx+=3;}
        		if(a[i][j]==11){add(id1,id2,1,0);add(id1,id3,1,0);add(id1,id5,1,0);add(id2,id4,1,2);add(id3,id4,1,1);add(id5,id4,1,1);maxx+=3;}
        		if(a[i][j]==13){add(id1,id2,1,0);add(id1,id4,1,0);add(id1,id5,1,0);add(id2,id3,1,1);add(id4,id3,1,1);add(id5,id3,1,2);maxx+=3;}
        		if(a[i][j]==14){add(id1,id3,1,0);add(id1,id4,1,0);add(id1,id5,1,0);add(id3,id2,1,1);add(id4,id2,1,2);add(id5,id2,1,1);maxx+=3;}    		
        		if(a[i][j]==5){add(id1,id2,1,0);add(id1,id4,1,0);maxx+=2;}
        		if(a[i][j]==10){add(id1,id3,1,0);add(id1,id5,1,0);maxx+=2;}
        		if(a[i][j]==15){add(id1,id2,1,0);add(id1,id3,1,0);add(id1,id4,1,0);add(id1,id5,1,0);maxx+=4;}
    		} else {
        		if(a[i][j]==1){add(id2,id1,1,0);add(id3,id2,1,1);add(id5,id2,1,1);add(id4,id2,1,2);maxx++;}
        		if(a[i][j]==2){add(id3,id1,1,0);add(id2,id3,1,1);add(id4,id3,1,1);add(id5,id3,1,2);maxx++;}
        		if(a[i][j]==4){add(id4,id1,1,0);add(id3,id4,1,1);add(id5,id4,1,1);add(id2,id4,1,2);maxx++;}
        		if(a[i][j]==8){add(id5,id1,1,0);add(id2,id5,1,1);add(id4,id5,1,1);add(id3,id5,1,2);maxx++;}
        		if(a[i][j]==3){add(id2,id1,1,0);add(id3,id1,1,0);add(id4,id2,1,1);add(id5,id3,1,1);maxx+=2;}
        		if(a[i][j]==6){add(id3,id1,1,0);add(id4,id1,1,0);add(id5,id3,1,1);add(id2,id4,1,1);maxx+=2;}
        		if(a[i][j]==9){add(id5,id1,1,0);add(id2,id1,1,0);add(id3,id5,1,1);add(id4,id2,1,1);maxx+=2;}
        		if(a[i][j]==12){add(id4,id1,1,0);add(id5,id1,1,0);add(id2,id4,1,1);add(id3,id5,1,1);maxx+=2;}
        	   	if(a[i][j]==7){add(id2,id1,1,0);add(id3,id1,1,0);add(id4,id1,1,0);add(id5,id2,1,1);add(id5,id3,1,2);add(id5,id4,1,1);maxx+=3;}
        		if(a[i][j]==11){add(id2,id1,1,0);add(id3,id1,1,0);add(id5,id1,1,0);add(id4,id2,1,2);add(id4,id3,1,1);add(id4,id5,1,1);maxx+=3;}
        		if(a[i][j]==13){add(id2,id1,1,0);add(id4,id1,1,0);add(id5,id1,1,0);add(id3,id2,1,1);add(id3,id4,1,1);add(id3,id5,1,2);maxx+=3;}
        		if(a[i][j]==14){add(id3,id1,1,0);add(id4,id1,1,0);add(id5,id1,1,0);add(id2,id3,1,1);add(id2,id4,1,2);add(id2,id5,1,1);maxx+=3;} 
        		if(a[i][j]==5){add(id2,id1,1,0);add(id4,id1,1,0);maxx+=2;}
        		if(a[i][j]==10){add(id3,id1,1,0);add(id5,id1,1,0);maxx+=2;}
        		if(a[i][j]==15){add(id2,id1,1,0);add(id3,id1,1,0);add(id4,id1,1,0);add(id5,id1,1,0);maxx+=4;}
        	}
        }
        for(re int i=1;i<=n;i++)
        	for(re int j=1;j<=m;j++){
        		if((i+j)%2==0){
        			if(i>1) add(id2,id4-m,1,0);
        			if(j>1) add(id5,id3-1,1,0);
        			if(i<n) add(id4,id2+m,1,0);
        			if(j<m) add(id3,id5+1,1,0);
        		}
        	}
        int d=max_flow();
        cout<<((maxx==d<<1)?tot:-1);
        return 0;
    }
    
  • 相关阅读:
    C语言基础-第一章
    C语言基础-第三章
    C语言基础-第五章
    怎样在WIN7系统下安装IIS
    Asp.Net中使用水晶报表(下)
    Asp.Net中使用水晶报表(中)
    Asp.Net 中使用 水晶报表(上)
    A1112. Stucked Keyboard
    A1111. Online Map
    A1110. Complete Binary Tree
  • 原文地址:https://www.cnblogs.com/victorique/p/8847078.html
Copyright © 2011-2022 走看看