2756: [SCOI2012]奇怪的游戏
来源:互联网 发布:java反射实现原理 编辑:程序博客网 时间:2024/06/05 00:27
题目链接
题目大意:在一个 N*M 的棋盘上玩,每个格子有一个数。每次 选择两个相邻的格子,并使这两个数都加上 1。 问最少多少次能使棋盘上的数都变成同一个数,如果永远不能变成同一个数则输出-1。
题解:黑白染色,每次操作使得黑白格子共和各自增加1
现在需要判断x是否可行,源点向黑色,白色向汇点连边,权值为x-格子的数字,相邻格子连边INF(可以无限次+1),满流即可
我的收获:分类讨论,强啊
#include <iostream>#include <cstring>#include <cstdio>#include <algorithm>using namespace std;const int M=45*45;#define INF 1e12const int dx[]={0,1,-1,0,0};const int dy[]={0,0,0,1,-1};int n,m,t,T,cnt,cnt0,cnt1,st,ed,mx;int mp[45][45],id[45][45],col[M][M],head[M],last[M],d[M],num[M];long long s0,s1,tot;bool Exit;struct edge{int to,nex;long long c;}e[M*20];void add(int u,int v,long long w){e[t].to=v,e[t].c=w,e[t].nex=head[u],last[u]=head[u]=t++;}void insert(int x,int y,long long z){add(x,y,z),add(y,x,0);};long long dfs(int x,long long in){ if(x==ed) return in; long long ans=0,f; for(int i=last[x];i!=-1;last[x]=i=e[i].nex) { int v=e[i].to; if(e[i].c&&d[v]==d[x]-1){ f=dfs(v,min(in-ans,e[i].c)); ans+=f;e[i].c-=f,e[i^1].c+=f; if(Exit||ans==in) return ans; } } if(--num[d[x]]==0) Exit=1; d[x]++,num[d[x]]++,last[x]=head[x]; return ans;}long long isap(){ Exit=0; long long flow=0; while(!Exit) flow+=dfs(st,INF); return flow;}void buildclear(){ memset(head,-1,sizeof(head)); memset(last,-1,sizeof(last)); memset(num,0,sizeof(num));//!!! memset(d,0,sizeof(d));//!!!!! st=0;ed=n*m+1;num[0]=n*m+2;t=0;tot=0;}void build(long long x){ buildclear(); for(int i=1;i<=n;i++) for(int j=1;j<=m;j++) if(col[i][j]) { insert(st,id[i][j],x-mp[i][j]);tot+=x-mp[i][j]; for(int k=1;k<=4;k++) { int fx=i+dx[k],fy=j+dy[k]; if(fx<1||fx>n||fy<1||fy>m) continue; insert(id[i][j],id[fx][fy],INF); } } else insert(id[i][j],ed,x-mp[i][j]);}bool check(long long x){ build(x); return isap()==tot;}void work(){ long long ans; if(cnt0!=cnt1) { ans=(s0-s1)/(cnt0-cnt1); if(check(ans)) {printf("%lld\n",ans*cnt1-s1); return ;} puts("-1"); } else { if(s0!=s1) {puts("-1");return ;} for(long long l=mx,r=INF;l<=r;){ long long mid=(l+r)>>1; if(check(mid)) r=mid-1,ans=mid; else l=mid+1; } printf("%lld\n",ans*cnt1-s1); }}void initclear(){mx=s0=cnt0=s1=cnt1=cnt=0;}void init(){ cin>>n>>m;initclear(); for(int i=1;i<=n;i++) for(int j=1;j<=m;j++) scanf("%d",&mp[i][j]),id[i][j]=++cnt,col[i][j]=(i+j)&1,mx=max(mx,mp[i][j]); for(int i=1;i<=n;i++) for(int j=1;j<=m;j++) if(col[i][j]) s1+=mp[i][j],cnt1++; else s0+=mp[i][j],cnt0++; }int main(){ cin>>T; while(T--) init(),work(); return 0;}
阅读全文
0 0
- 2756: [SCOI2012]奇怪的游戏
- 2756: [SCOI2012]奇怪的游戏
- SCOI2012[奇怪的游戏]
- BZOJ 2756 [SCOI2012]奇怪的游戏
- BZOJ 2756 [SCOI2012]奇怪的游戏
- BZOJ 2756 SCOI2012 奇怪的游戏
- bzoj2756: [SCOI2012]奇怪的游戏
- [BZOJ2756][SCOI2012]奇怪的游戏
- BZOJ2756/SCOI2012 奇怪的游戏
- bzoj2756 [SCOI2012]奇怪的游戏
- bzoj2756 [SCOI2012]奇怪的游戏
- bzoj2756 [SCOI2012]奇怪的游戏
- 【SCOI2012】bzoj2756 奇怪的游戏
- bzoj2756 [SCOI2012]奇怪的游戏
- BZOJ2756 [SCOI2012]奇怪的游戏
- bzoj 2756: [SCOI2012]奇怪的游戏(网络流+二分)
- 【BZOJ 2756】[SCOI2012]奇怪的游戏 网络流+二分
- Dinic最大流(bzoj 2756: [SCOI2012]奇怪的游戏)
- ArrayList、LinkedList、Vector的区别
- HDU 2089:不要62
- 和为S的连续正数序列
- O(1)时间检测2的幂
- Android 安装错误总结
- 2756: [SCOI2012]奇怪的游戏
- C++primerplus知识总结二 (类知识点)
- Thinkphp 控制器->前置操作和后置操作
- 简单的数组循环操作
- 突出显示错误的可访问性
- c++之构造函数
- 独立的小易
- 剑指offer:求1+2+3+...+n
- BZOJ1257: [CQOI2007]余数之和sum【分块】