BZOJ2756/SCOI2012 奇怪的游戏

来源:互联网 发布:彩影软件 arp 编辑:程序博客网 时间:2024/06/08 07:00

思路:
首先网络流在网格上经常用到黑白染色。其次如果涉及到一些平衡(相等之类)经常可以列流量平衡方程方程求解。
hzwer有很好的题解。这里只是贴代码。

/**************************************************************    Problem: 2756    User: DtenSherlock    Language: C++    Result: Accepted    Time:12568 ms    Memory:2888 kb****************************************************************/#include<iostream>#include<cstdio>#include<cstdlib>#include<algorithm>#include<cmath>#include<cstring>#include<string>#include<queue>using namespace std;typedef long long LL;const int imax=40+9;const int dmax=2290;const int bmax=100000+229;const LL inf=1LL<<61;const int dx[4]={0,0,1,-1};const int dy[4]={1,-1,0,0};int TT,n,m,id[imax][imax],tot; LL a[imax][imax];int S,T,num,head[dmax],to[bmax],inext[bmax]; LL re[bmax];void iread(){    scanf("%d%d",&n,&m);    tot=0;    for(int i=1;i<=n;i++)        for(int j=1;j<=m;j++)             scanf("%lld",&a[i][j]),id[i][j]=++tot;}int d[dmax]; queue<int>q;bool BFS(){    memset(d,0,sizeof(d));    q.push(S); d[S]=1;    while(!q.empty())    {        int u=q.front(); q.pop();        for(int i=head[u];i!=-1;i=inext[i])            if(re[i] && !d[to[i]])            {                d[to[i]]=d[u]+1;                q.push(to[i]);              }       }       return d[T]>0;}LL DFS(int x,LL c){    if(x==T || c==0) return c;    LL r=c;    for(int i=head[x];i!=-1;i=inext[i])        if(d[to[i]]==d[x]+1)        {            LL f=DFS(to[i],min(re[i],r));            r-=f; re[i]-=f; re[i^1]+=f;            if(!r) break;           }    if(r==c) d[x]=0;    return c-r;     }void iadd(int u,int v,LL flow){ to[num]=v; re[num]=flow; inext[num]=head[u]; head[u]=num++;}void add(int u,int v,LL flow) { iadd(u,v,flow); iadd(v,u,0);}bool pd(LL delta){    S=0; T=n*m+1;     for(int i=S;i<=T;i++) head[i]=-1;    num=0; LL sum=0;    for(int i=1;i<=n;i++)        for(int j=1;j<=m;j++)        {            if((i+j)&1) add(S,id[i][j],delta-a[i][j]),sum+=delta-a[i][j];            else add(id[i][j],T,delta-a[i][j]);            if(!((i+j)&1)) continue;            for(int k=0;k<4;k++)            {                int nowx=i+dx[k];                int nowy=j+dy[k];                if(nowx<1 || nowx>n || nowy<1 || nowy>m) continue;                add(id[i][j],id[nowx][nowy],inf);               }           }    LL nowans=0;    while(BFS()) nowans+=DFS(S,inf);    return (nowans==sum);}void iwork(){    LL sum1=0; LL sum2=0; LL Max=0; int num1=0; int num2=0;    for(int i=1;i<=n;i++)        for(int j=1;j<=m;j++)        {            if((i+j)&1) num1++,sum1+=a[i][j];               else num2++,sum2+=a[i][j];            Max=max(Max,a[i][j]);        }       if(num1!=num2)    {        LL x=(sum1-sum2)/(num1-num2);        if(x>=Max)        {            if(pd(x))            {                printf("%lld\n",(x*num1-sum1));                 return;            }           }           puts("-1");    }    else    {        LL l=Max; LL r=inf;        while(l<=r)        {        //  printf("%lld %lld\n",l,r);            if(l+1==r || l==r)            {                if(pd(l)) r=l;                break;              }               LL Mid=(l+r)>>1;            if(pd(Mid)) r=Mid;            else l=Mid+1;        }        if(pd(r)) { printf("%lld\n",r*num1-sum1); return;}        puts("-1");     }}int main(){    scanf("%d",&TT);    while(TT--)    {        iread();        iwork();        }    return 0;}
0 0