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();
        } 
    }
    
  • 相关阅读:
    webrtcvad模块使用
    pyroomacoustics--生成房间脉冲响应
    virtualbox设置了共享文件夹却无权限访问
    机器学习-高斯判别分析
    机器学习--线性判别分析
    阵列信号处理-波束加权
    线性分类-感知机
    vbox虚拟机扩容(CentOS 7.2)
    安装MySQLdb模块遭遇"fatal error: my_config.h: No such file or directory"的处理
    使用git bash编译安装sysbench时遇到的坑
  • 原文地址:https://www.cnblogs.com/zy691357966/p/5480321.html
Copyright © 2011-2022 走看看