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;
}
posted @ 2018-04-15 13:03  ~victorique~  阅读(187)  评论(1编辑  收藏  举报
Live2D