2756: [SCOI2012]奇怪的游戏

来源:互联网 发布:java反射实现原理 编辑:程序博客网 时间:2024/06/05 00:27

题目链接

题目大意:在一个 N*M 的棋盘上玩,每个格子有一个数。每次 选择两个相邻的格子,并使这两个数都加上 1。 问最少多少次能使棋盘上的数都变成同一个数,如果永远不能变成同一个数则输出-1。

题解:黑白染色,每次操作使得黑白格子共和各自增加1
cnt1,s1cnt2,s2x,有

xcnt1s1=xcnt2s2

(1)cnt1!=cnt2xx=(s1s2)/(cnt1cnt2)
(2)cnt1=cnt2xxx

现在需要判断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;}
原创粉丝点击