【网络流】【1010】【棋盘加数】

题目大意

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

  • 显然有黑白染色的特征
  • 显然是二分图
  • 黑色和白色的数值差永远不变
  • 如果知道变成什么数,可以用网络流来判断是否可以

做法

  • 如果N或M为偶数可以二分+网络流解决
  • 如果N和M都为奇数可以利用以下等式

(黑色格子数-白色格子数)*最终情况格子的值=黑色初始格子总值-白色初始格子总值
得到最终情况格子的值,所以为奇数的时候是一个确定的值

坑点

  • 注意MAXN,MAXM的确定,小了的话,会超时,很难发现是因为这个超时的!!!
  • long long

代码

#include <cstdio>  
#include <cstdlib>  
#include <cmath>  
#include <cstring>  
#include <ctime>  
#include <algorithm>  
#include <iostream>
#include <sstream>
#include <string>
#define oo 0x13131313   
using namespace std;
const int MAXN=2000+5;
const int MAXM=10000;
long long INF=1LL<<50;
int ok=1;
int fx[5]={0,0,0,1,-1},fy[6]={0,1,-1,0,0};
struct Edge
{
    long long to,next,cap,flow;
    void get(long long a,long long b,long long c,long long d)
    {
        to=a;next=b;cap=c;flow=d;
    }
}edge[MAXM];
long long tol;
long long head[MAXN];
long long gap[MAXN],dep[MAXN],pre[MAXN],cur[MAXN];
void init()
{
    tol=0;
    memset(head,-1,sizeof(head));
}
//¦Ì£¤&#207;¨°¨ª&#188;¨¨y&#184;&#246;2&#206;¨ºy¡ê&#172;&#206;T&#207;¨°¨ª&#188;&#203;&#196;&#184;&#246;2&#206;¨ºy
void addedge(long long u,long long v,long long w,long long rw=0)
{
    edge[tol].get(v,head[u],w,0);head[u]=tol++;
    edge[tol].get(u,head[v],rw,0);head[v]=tol++;
}
long long sap(long long start,long long end,long long N)
{
    memset(gap,0,sizeof(gap));
    memset(dep,0,sizeof(dep));
    memcpy(cur,head,sizeof(head));
    long long u=start;
    pre[u]=-1;
    gap[0]=N;
    long long ans=0;
    while(dep[start]<N)
    {
        if(u==end)
        {
            long long Min=INF;
            for(long long i=pre[u];i!=-1;i=pre[edge[i^1].to])
                if(Min>edge[i].cap-edge[i].flow)
                   Min=edge[i].cap-edge[i].flow;
            for(long long i=pre[u];i!=-1;i=pre[edge[i^1].to])
            {
                edge[i].flow+=Min;
                edge[i^1].flow-=Min;
            }
            u = start;
            ans+=Min;
            continue;
        }
        bool flag=false;
        long long v;
        for(long long i=cur[u];i !=-1;i=edge[i].next)
        {
            v=edge[i].to;
            if(edge[i].cap-edge[i].flow&&dep[v]+1==dep[u])
            {
                flag=true;
                cur[u]=pre[v]=i;
                break;
            }
        }
        if(flag)
        {
            u=v;
            continue;
        }
        long long Min=N;
        for(long long i=head[u];i!=-1;i=edge[i].next)
            if(edge[i].cap-edge[i].flow&&dep[edge[i].to]<Min)
        {
            Min=dep[edge[i].to];
            cur[u]=i;
        }
        gap[dep[u]]--;
        if(!gap[dep[u]]) return ans;
        dep[u]=Min+1;
        gap[dep[u]]++;
        if(u!=start) u=edge[pre[u]^1].to;
    }
    return ans;
}
long long N,M;
long long s,t,NN;
long long MAP[100][100];
long long b=0,w=0;
long long sum=0;
long long nb,nw;
void input()
{
    nb=0,nw=0;
    b=0,w=0;sum=0;
    cin>>N>>M;
    for(long long i=1;i<=N;i++)
        for(long long j=1;j<=M;j++)
        {
            scanf("%I64d",&MAP[i][j]);
            sum+=MAP[i][j];
            if((i+j)%2==0)
            b=b+MAP[i][j],nb++;
            else 
            w=w+MAP[i][j],nw++;
        }
}
void creatgraph(long long c)
{
    init();
    s=0;t=N*M+1;
    //s-> && ->oo
    for(int i=1;i<=N;i++)
        for(int j=1;j<=M;j++)
        {       
            if((i+j)%2==0)
            {
            if(c-MAP[i][j]>=0)
            addedge(s,(i-1)*M+j,c-MAP[i][j]);
            else ok=0;
            for(int k=1;k<=4;k++)
                {
                    long long xx=i+fx[k],yy=j+fy[k];
                    if(1<=xx&&xx<=N&&1<=yy&&yy<=M)
                                                { 
                        //debug
                    //  printf("%d %d->%d %d\n",i,j,xx,yy);
                        addedge((i-1)*M+j,(xx-1)*M+yy,INF);
                    }
                }
            }
        } 
    //->t
    for(long long i=1;i<=N;i++)
        for(long long j=1;j<=M;j++)
        {
            if((i+j)%2==1)
            if(c-MAP[i][j]>=0)
            addedge((i-1)*M+j,t,c-MAP[i][j]);
            else ok=0;
        } 
}
void solve1()
{
    if(w!=b) {
        printf("-1\n");
        return ;
    }
    else {
        long long l=0,r=1LL<<40;
        while(l<r)
        {   
            long long m=(l+r)/2;
            ok=1;
            creatgraph(m);
            long long a=sap(s,t,N*M+2);
            long long b=(N*M*m-sum)/2;
    //      printf("%I64d %I64d\n",a,b);
            if(a==b&&ok==1) r=m;
            else l=m+1;     
        }
        printf("%I64d\n",(N*M*l-sum)/2);
    }
}
void solve2()
{
    if(b>w)
    {
        long long m=b-w;
        creatgraph(m);
        if(sap(s,t,N*M+2)==(N*M*m-sum)/2)
        printf("%I64d\n",(N*M*m-sum)/2);
        else printf("-1\n");
    }
    else printf("-1\n");
} 
int main()
{
//  freopen("a.in","r",stdin);
    long long T;
    cin>>T;
    while(T--)
    {
        ok=1;
        input();
        if(N%2==0||M%2==0)
        solve1();
        else solve2();
    } 
}

posted on 2015-09-10 14:43  DDUPzy  阅读(183)  评论(0编辑  收藏  举报

导航