zoukankan      html  css  js  c++  java
  • [BZOJ5120]无限之环

    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度,这样就使得水管封闭了

    样例 2 为题目描述中的第一张图片,无法达成目标。

    样例 3 为题目描述中的第二张图片,将除了中心方格以外的每个方格内的水管都转 180 度即可。


    看题解之前一脸懵逼……看完题解后大骂自己是zz……

    首先我们黑白染色,分成黑白两部分,S向白点连边,黑点向T连边

    然后考虑触点的方向有4个,那么我们显然把每个点拆成5个点,上下左右各一个,外加自己这个中心点

    然后我们就可以考虑连边,然后旋转有费用,我们就建图跑费用流,那么,怎么连边?或者说,如何控制边的流量和费用?

    分类讨论?讨论旋转后每个触点的出边?恭喜你,你可能会讨论到死去活来,甚至最后会TLE

    其实我们已经拆完点了,那么我们只需要在内部讨论费用问题即可,根本不需要考虑旋转后触点的出边

    第一种:单触点

    这个好办,它原本指向哪个方向,我们让中心点连向该方向的小点,流量为1,费用为0;至于旋转,我们只需要让小点连向其他小点即可,流量为(infty),费用分别为1,2,1(蛤?你问我哪个是1,哪个是2?这种事自己画个图判断去吧,反正不难)

    第二种:双触点

    直线型直接pass吧(不知道为什么赶快看题去,这东西我整半天没整明白咋连费用,最后发现题目不让旋转)

    拐角型的话,我们假定触点在上右两侧,那么我们中心点就连出两条流量为1,费用为0的边出来;然后考虑旋转,就让上侧小点向下侧小点连一条流量为(infty),费用为1的边,右向左也如此。然后你稍作模拟,发现不管拐角型转成啥样,费用都是对的

    第三种:三触点

    其实和单触点类似,不过在连出三条费用为0的边后,直接连接的三个小点分别向空出来的小点连一条流量为(infty),费用分别为1,2,1的边(说了和单触点类似,所以自己画图稍微判下吧)

    第四种:全触点

    那就全连边呗,都是费用为0的

    然后图建完了,直接上最小费用最大流即可

    然后这是EK费用流和Dinic费用流的区别……不说了,以后都用Dinic了……

    /*program from Wolfycz*/
    #include<cmath>
    #include<cstdio>
    #include<cstring>
    #include<iostream>
    #include<algorithm>
    #define inf 0x7f7f7f7f
    #define lowbit(x) ((x)&-(x))
    using namespace std;
    typedef long long ll;
    typedef long double ld;
    typedef unsigned int ui;
    typedef unsigned long long ull;
    inline char gc(){
    	static char buf[1000000],*p1=buf,*p2=buf;
    	return p1==p2&&(p2=(p1=buf)+fread(buf,1,1000000,stdin),p1==p2)?EOF:*p1++;
    }
    inline int frd(){
    	int x=0,f=1; char ch=gc();
    	for (;ch<'0'||ch>'9';ch=gc())	if (ch=='-')	f=-1;
    	for (;ch>='0'&&ch<='9';ch=gc())	x=(x<<3)+(x<<1)+ch-'0';
    	return x*f;
    }
    inline int read(){
    	int x=0,f=1; char ch=getchar();
    	for (;ch<'0'||ch>'9';ch=getchar())	if (ch=='-')	f=-1;
    	for (;ch>='0'&&ch<='9';ch=getchar())	x=(x<<3)+(x<<1)+ch-'0';
    	return x*f;
    }
    inline void print(int x){
    	if (x<0)	putchar('-'),x=-x;
    	if (x>9)	print(x/10);
    	putchar(x%10+'0');
    }
    const int N=1e4+2,M=4e4;
    const int dx[4]={-1,0,1,0};
    const int dy[4]={0,1,0,-1};
    int pre[M+10],now[N+10],child[M+10],val[M+10],cost[M+10];
    int dis[N+10],deep[N+10];
    int n,m,S,T,All,tot=1;
    void join(int x,int y,int z,int v){pre[++tot]=now[x],now[x]=tot,child[tot]=y,val[tot]=z,cost[tot]=v;}
    void insert(int x,int y,int z,int v,bool flag=1){
    	if (!flag)	swap(x,y);
    	join(x,y,z,v),join(y,x,0,-v);
    }
    int G(int x,int y){return (x-1)*m+y;}
    bool in_map(int x,int y){return x>0&&x<=n&&y>0&&y<=m;}
    bool SPFA(){
    	memset(dis,63,sizeof(dis));
    	memset(deep,255,sizeof(deep));
    	static int h[N+10];
    	static bool vis[N+10];
    	int head=0,tail=1;
    	h[1]=S,vis[S]=1,dis[S]=deep[S]=0;
    	while (head!=tail){
    		if (++head>N)	head=1;
    		int Now=h[head];
    		for (int p=now[Now],son=child[p];p;p=pre[p],son=child[p]){
    			if (val[p]>0&&dis[son]>dis[Now]+cost[p]){
    				dis[son]=dis[Now]+cost[p];
    				deep[son]=deep[Now]+1;
    				if (!vis[son]){
    					if (++tail>N)	tail=1;
    					vis[h[tail]=son]=1;
    				}
    			}
    		}
    		vis[Now]=0;
    	}
    	return ~deep[T];
    }
    int dfs(int x,int v){
    	if (x==T)	return v;
    	int res=0;
    	for (int p=now[x],son=child[p];p;p=pre[p],son=child[p]){
    		if (val[p]>0&&deep[son]>deep[x]&&dis[son]==dis[x]+cost[p]){
    			int k=dfs(son,min(v,val[p]));
    			res+=k,v-=k;
    			val[p]-=k,val[p^1]+=k;
    			if (!v)	break;
    		}
    	}
    	if (!res)	deep[x]=-1;
    	return res;
    }
    int MCMF(int Ans_Flow){
    	int Max_Flow=0,Min_cost=0;
    	while (SPFA()){
    		int res=dfs(S,inf);
    		Max_Flow+=res;
    		Min_cost+=res*dis[T];
    	}
    	return Max_Flow==Ans_Flow?Min_cost:-1;
    }
    int main(){
    	static int g[16]; g[0]=0;
    	for (int i=1;i<16;i++)	g[i]=g[i-lowbit(i)]+1;
    	n=read(),m=read(),All=n*m,S=All*5+1,T=S+1;
    	int Ans_Flow1=0,Ans_Flow2=0;
    	for (int i=1;i<=n;i++){
    		for (int j=1;j<=m;j++){
    			int x=read();
    			if ((i+j)&1){
    				insert(S,G(i,j),inf,0);
    				Ans_Flow1+=g[x];
    				for (int k=0;k<4;k++){
    					int tx=i+dx[k],ty=j+dy[k];
    					if (!in_map(tx,ty))	continue;
    					insert(All*(k+1)+G(i,j),All*((k+2)%4+1)+G(tx,ty),1,0);
    				}
    			}else{
    				insert(G(i,j),T,inf,0);
    				Ans_Flow2+=g[x];
    			}
    			if (!g[x])	continue;
    			if (g[x]==1){
    				for (int k=0;k<4;k++){
    					if (x>>k&1){
    						insert(G(i,j),All*(k+1)+G(i,j),1,0,(i+j)&1);
    						insert(All*(k+1)+G(i,j),All*((k+1)%4+1)+G(i,j),inf,1,(i+j)&1);
    						insert(All*(k+1)+G(i,j),All*((k+2)%4+1)+G(i,j),inf,2,(i+j)&1);
    						insert(All*(k+1)+G(i,j),All*((k+3)%4+1)+G(i,j),inf,1,(i+j)&1);
    						break;
    					}
    				}
    			}
    			if (g[x]==2){
    				int ID_1=-1,ID_2=-1;
    				for (int k=0;k<4;k++)	if (x>>k&1)	!~ID_1?ID_1=k:ID_2=k;
    				insert(G(i,j),All*(ID_1+1)+G(i,j),1,0,(i+j)&1);
    				insert(G(i,j),All*(ID_2+1)+G(i,j),1,0,(i+j)&1);
    				if (ID_2-ID_1==2)	continue;
    				insert(All*(ID_1+1)+G(i,j),All*((ID_1+2)%4+1)+G(i,j),inf,1,(i+j)&1);
    				insert(All*(ID_2+1)+G(i,j),All*((ID_2+2)%4+1)+G(i,j),inf,1,(i+j)&1);
    			}
    			if (g[x]==3){
    				for (int k=0;k<4;k++){
    					if (!(x>>k&1)){
    						insert(G(i,j),All*((k+1)%4+1)+G(i,j),1,0,(i+j)&1);
    						insert(G(i,j),All*((k+2)%4+1)+G(i,j),1,0,(i+j)&1);
    						insert(G(i,j),All*((k+3)%4+1)+G(i,j),1,0,(i+j)&1);
    						insert(All*((k+1)%4+1)+G(i,j),All*(k+1)+G(i,j),inf,1,(i+j)&1);
    						insert(All*((k+2)%4+1)+G(i,j),All*(k+1)+G(i,j),inf,2,(i+j)&1);
    						insert(All*((k+3)%4+1)+G(i,j),All*(k+1)+G(i,j),inf,1,(i+j)&1);
    						break;
    					}
    				}
    			}
    			if (g[x]==4)
    				for (int k=0;k<4;k++)
    					insert(G(i,j),All*(k+1)+G(i,j),inf,0,(i+j)&1);
    		}
    	}
    	int Ans_Flow=max(Ans_Flow1,Ans_Flow2);
    	printf("%d
    ",MCMF(Ans_Flow));
    	return 0;
    }
    
  • 相关阅读:
    线程queue
    定时器
    event模拟数据库链接
    最速下降法(梯度下降法)
    神经网络中的反向传播算法
    批量学习和在线学习的区别
    LMS算法
    粒子群算法
    遗传算法
    logistic回归
  • 原文地址:https://www.cnblogs.com/Wolfycz/p/10392867.html
Copyright © 2011-2022 走看看