zoukankan      html  css  js  c++  java
  • 【网络流】【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
    ",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
    ");
            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
    ",a,b);
                if(a==b&&ok==1) r=m;
                else l=m+1;     
            }
            printf("%I64d
    ",(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*M*m-sum)/2);
            else printf("-1
    ");
        }
        else printf("-1
    ");
    } 
    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();
        } 
    }
    
  • 相关阅读:
    防火墙透明模式
    HP管理工具System Management Homepage安装配置
    kbmmw 中JSON 中使用SQL 查询
    kbmmw 中JSON 操作入门
    第一个kbmmw for Linux 服务器
    kbmmw 5.02发布
    kbmmw 5.01 发布
    使用delphi 10.2 开发linux 上的Daemon
    使用unidac 在linux 上无驱动直接访问MS SQL SERVER
    使用delphi 10.2 开发linux 上的webservice
  • 原文地址:https://www.cnblogs.com/zy691357966/p/5480321.html
Copyright © 2011-2022 走看看