刷题总结——奇怪的游戏(scoi2012)
题目:
题目描述
Blinker 最近喜欢上一个奇怪的游戏。
这个游戏在一个 N*M 的棋盘上玩,每个格子有一个数。每次 Blinker 会选择两个相邻的格子,并使这两个数都加上 1。
现在 Blinker 想知道最少多少次能使棋盘上的数都变成同一个数,如果永远不能变成同一个数则输出 -1。
输入格式
输入的第一行是一个整数 T,表示输入数据有T 轮游戏组成。
每轮游戏的第一行有两个整数 N 和 M , 分别代表棋盘的行数和列数。
接下来有 N 行,每行 M 个数。
输出格式
对于每个游戏输出最少能使游戏结束的次数,如果永远不能变成同一个数则输出 -1。
样例数据 1
备注
【数据范围】
对于 30% 的数据,保证 T<=10,1<=N,M<=8
对于 100% 的数据,保证 T<= 10,1<=N,M<=40,所有数为正整数且小于 1000000000
题解:
这里引用http://www.cnblogs.com/DaD3zZ-Beyonder/p/5765882.html:
一道比较有趣的题目
先对题目进行分析:
首先我们考虑对棋盘黑白染色,那么我们发现:“每次相邻两个+1”,显然是一黑一白+1
那么我们先统计出WhiteNum,BlackNum(黑白点的数目),WhiteSum,BlackSum(黑白点初始权值和)(接下来可能用Wn,Ws,Bn,Bs代替)
那么对于一次增加,显然是WhiteSum+1,BlackSum+1
考虑对最后的情况进行讨论:
那么很显然,当WhiteNum==BlackNum时(即总点数为偶数)
如果WhiteSum!=BlackSum,显然无解
如果WhiteSum==BlackSum时,我们发现,对于X如果成立,那么X+1一定成立,显然满足二分的性质,那么二分这个值,进行判定
当WhiteNum!=BlackNum时(即总点数为奇数)
发现显然,若有解,则解唯一,那么直接验证正确性即可
至于解怎么求?
设最后所有数变为X,易得X*Wn-Ws=X*Bn-Bs,整理下可得:X=(Ws-Bs)/(Wn-Bn),用网络流验证即可
那么考虑建图:
S-->白点,约束为X-val[i][j]
黑点-->T,约束为X-val[i][j]
相邻的白点-->黑点,约束为INF
判断是否满流即可
最后说下个人心得:
这道题的重点其实不是网络流,而是黑白染色这一想法,由相邻格子染色其实可以考虑到这一点,以后做到相似的题要注意这一想法····然后就是后面的分类讨论···也是由黑白染色后考虑答案的性质得出的·····这是一道很好的题,染色+二分+网络流;
代码
#include<iostream> #include<cstdio> #include<cstdlib> #include<cmath> #include<ctime> #include<cctype> #include<cstring> #include<string> #include<algorithm> using namespace std; const int N=2010; const int M=1001000; const long long inf=1e+18; int Ri() { char c; int f=0; for(c=getchar();c<'0'||c>'9';c=getchar()); for(;c<='9'&&c>='0';c=getchar()) f=(f<<3)+(f<<1)+c-'0'; return f; } long long Rl() { char c; long long f=0; for(c=getchar();c<'0'||c>'9';c=getchar()); for(;c<='9'&&c>='0';c=getchar()) f=f*10+c-'0'; return f; } int T,n,m,tot,first[N],cur[N],lev[N],next[M],go[M],Wn,Bn,src,des; int color[N][N],num[N][N]; long long map[N][N],rest[M],Ws,Bs,ans,sum; inline void comb(int a,int b,long long c) { next[++tot]=first[a],first[a]=tot,go[tot]=b,rest[tot]=c; next[++tot]=first[b],first[b]=tot,go[tot]=a,rest[tot]=0; } inline bool bfs() { for(int i=src;i<=des;i++) cur[i]=first[i],lev[i]=-1; static int que[N],tail,u,v; que[tail=1]=src; lev[src]=0; for(int head=1;head<=tail;head++) { u=que[head]; for(int e=first[u];e;e=next[e]) { if(lev[v=go[e]]==-1&&rest[e]) { lev[v]=lev[u]+1; que[++tail]=v; if(v==des) return true; } } } return false; } inline long long dinic(int u,long long flow) { if(u==des) return flow; long long res=0,delta; int v; for(int &e=cur[u];e;e=next[e]) { if(lev[v=go[e]]>lev[u]&&rest[e]) { delta=dinic(v,min(flow-res,rest[e])); if(delta) { rest[e]-=delta; rest[e^1]+=delta; res+=delta; if(res==flow) break; } } } if(flow!=res) lev[u]=-1; return res; } inline long long maxflow() { long long temp=0; while(bfs()) temp+=dinic(src,inf); return temp; } inline bool jud(int x,int y) { return x>=1&&x<=n&&y>=1&&y<=m; } inline bool check(long long lim) { tot=1; memset(first,0,sizeof(first)); for(int i=1;i<=n;i++) for(int j=1;j<=m;j++) { if( !color[i][j]) comb(src,num[i][j],lim-map[i][j]); else comb(num[i][j],des,lim-map[i][j]); } for(int i=1;i<=n;i++) for(int j=1;j<=m;j++) if(!color[i][j]) { if(jud(i-1,j)) comb(num[i][j],num[i-1][j],inf); if(jud(i+1,j)) comb(num[i][j],num[i+1][j],inf); if(jud(i,j-1)) comb(num[i][j],num[i][j-1],inf); if(jud(i,j+1)) comb(num[i][j],num[i][j+1],inf); } long long temp=maxflow(); if(temp==((long long)Wn*lim-Ws)) return true; else return false; } inline void solve() { Wn=Ws=Bn=Bs=0; src=0; des=n*m+1; int cnt=0; long long left=0,right=1e+18; for(int i=1;i<=n;i++) for(int j=1;j<=m;j++) { num[i][j]=++cnt; color[i][j]=(i+j)%2; if(!color[i][j]) Wn++,Ws+=map[i][j]; else Bn++,Bs+=map[i][j]; left=max(left,map[i][j]); } if(Wn==Bn) { if(Ws!=Bs) { cout<<"-1"<<endl; return; } else { while(left<=right) { long long mid=(left+right)/2; if(check(mid)) ans=mid,right=mid-1; else left=mid+1; } cout<<ans*Wn-Ws<<endl; } } else { ans=(long long)(Ws-Bs)/(Wn-Bn); if(ans<left) { cout<<"-1"<<endl; return; } if(check(ans)) { cout<<ans*Wn-Ws<<endl; return; } else cout<<"-1"<<endl; } } int main() { // freopen("a.in","r",stdin); T=Ri(); while(T--) { n=Ri(),m=Ri(); for(int i=1;i<=n;i++) for(int j=1;j<=m;j++) map[i][j]=Rl(); solve(); } return 0; }