Description
Blinker最近喜欢上一个奇怪的游戏。
这个游戏在一个 N*M 的棋盘上玩,每个格子有一个数。每次 Blinker 会选择两个相邻
的格子,并使这两个数都加上 1。
现在 Blinker 想知道最少多少次能使棋盘上的数都变成同一个数,如果永远不能变成同
一个数则输出-1。
Input
输入的第一行是一个整数T,表示输入数据有T轮游戏组成。
每轮游戏的第一行有两个整数N和M, 分别代表棋盘的行数和列数。
接下来有N行,每行 M个数。
Output
对于每个游戏输出最少能使游戏结束的次数,如果永远不能变成同一个数则输出-1。
Sample Input
2
2 2
1 2
2 3
3 3
1 2 3
2 3 4
4 3 2
2 2
1 2
2 3
3 3
1 2 3
2 3 4
4 3 2
Sample Output
2
-1
-1
HINT
【数据范围】
对于30%的数据,保证 T<=10,1<=N,M<=8
对于100%的数据,保证 T<=10,1<=N,M<=40,所有数为正整数且小于1000000000
这TM哪是人做的题根本想不出来
黑白染色,然后不会
没题解会死系列
首先有两种情况:
设黑棋子出现次数为B,权值和为Black,白色为W,和为White
设黑棋子出现次数为B,权值和为Black,白色为W,和为White
如果B==W:
如果Black!=white,那么就无解。至于怎么解释,我不是很会说,
应该就似棋盘问题的东西(挖掉对角两个格子,就不能用长度为2宽度为1的骨牌完全覆盖)
那么如果相等,一定有解,那么就二分枚举ans,设ans为最终每个格子最终的值,
然后 ST->Black ans-a[i][j]
Black->White INF
White->ED ans-a[i][j]
如果B!=W:
那么就推柿子,验证答案即可
那么就推柿子,验证答案即可
黄学长博客:传送门
代码如下:
#include<cmath> #include<cstdio> #include<cstdlib> #include<cstring> #include<algorithm> using namespace std; typedef long long ll; struct node{ int x,y,next,other; ll c; }a[71000];int len,last[71000]; const ll INF=(1ll<<60); void ins(int x,int y,ll c) { int k1,k2; k1=++len; a[len].x=x;a[len].y=y;a[len].c=c; a[len].next=last[x];last[x]=len; k2=++len; a[len].x=y;a[len].y=x;a[len].c=0; a[len].next=last[y];last[y]=len; a[k1].other=k2; a[k2].other=k1; } int st,ed,h[81000]; int head,tail,list[21000]; bool bt_h() { memset(h,0,sizeof(h));h[st]=1; list[1]=st;head=1;tail=2; while(head!=tail) { int x=list[head]; for(int k=last[x];k;k=a[k].next) { int y=a[k].y; if(h[y]==0&&a[k].c>0) { h[y]=h[x]+1; list[tail++]=y; } } head++; } if(h[ed]>0)return true; return false; } /* 3 3 10 9 8 1 4 1 5 3 7 */ ll findflow(int x,ll f) { if(x==ed)return f; ll s=0,t; for(int k=last[x];k;k=a[k].next) { int y=a[k].y; if(h[y]==h[x]+1&&a[k].c>0&&s<f) { s+=(t=findflow(y,min(a[k].c,f-s))); a[k].c-=t;a[a[k].other].c+=t; } } if(s==0)h[x]=0; return s; } int f[61][61]; int n,m; int p[61][61],cnt; ll c[61][61]; ll black,white,b,w; bool check(ll x) { ll tot=0; len=0;memset(last,0,sizeof(last)); for(int i=1;i<=n;i++) for(int j=1;j<=m;j++) { if(f[i][j]==1) { ins(st,p[i][j],x-c[i][j]);tot+=x-c[i][j]; if(i>1)ins(p[i][j],p[i-1][j],INF); if(j>1)ins(p[i][j],p[i][j-1],INF); if(i<n)ins(p[i][j],p[i+1][j],INF); if(j<m)ins(p[i][j],p[i][j+1],INF); } else ins(p[i][j],ed,x-c[i][j]); } ll sum=0; while(bt_h()==true) sum+=findflow(st,INF); if(sum==tot)return true; return false; } int main() { int T;ll mx; scanf("%d",&T); while(T--) { cnt=0;mx=0; scanf("%d%d",&n,&m);st=0,ed=n*m+1; for(int i=1;i<=n;i++) for(int j=1;j<=m;j++) scanf("%lld",&c[i][j]),p[i][j]=++cnt,mx=max(mx,c[i][j]); black=white=b=w=0; for(int i=1;i<=n;i++) for(int j=1;j<=m;j++) { f[i][j]=(i+j)&1; if(f[i][j]==1)black++,b+=c[i][j]; else white++,w+=c[i][j]; } if(black==white) { if(b!=w)printf("-1\n"); else { ll l=mx,r=INF; while(l<=r) { ll mid=(l+r)/2; if(check(mid)==true)r=mid-1; else l=mid+1; } printf("%lld\n",l*black-b); } } else { ll ans=(w-b)/(white-black); if(check(ans)==true){ if(ans>=mx) printf("%lld\n",ans*black-b);} else printf("-1\n"); } } return 0; }
by_lmy