zoukankan      html  css  js  c++  java
  • BZOJ-2756 奇怪的游戏 黑白染色+最大流+当前弧优化+二分判断+分类讨论

    这个题的数据,太卡了,TLE了两晚上,各种调试优化,各种蛋疼。
    

    2756: [SCOI2012]奇怪的游戏
    Time Limit: 40 Sec Memory Limit: 128 MB
    Submit: 2311 Solved: 598
    [Submit][Status][Discuss]

    Description
    Blinker最近喜欢上一个奇怪的游戏。
    这个游戏在一个 N*M 的棋盘上玩,每个格子有一个数。每次 Blinker 会选择两个相邻
    的格子,并使这两个数都加上 1。
    现在 Blinker 想知道最少多少次能使棋盘上的数都变成同一个数,如果永远不能变成同
    一个数则输出-1。

    Input
    输入的第一行是一个整数T,表示输入数据有T轮游戏组成。
    每轮游戏的第一行有两个整数N和M, 分别代表棋盘的行数和列数。
    接下来有N行,每行 M个数。

    Output
    对于每个游戏输出最少能使游戏结束的次数,如果永远不能变成同一个数则输出-1。

    Sample Input
    2
    2 2
    1 2
    2 3
    3 3
    1 2 3
    2 3 4
    4 3 2

    Sample Output
    2
    -1

    HINT
    【数据范围】
    对于30%的数据,保证 T<=10,1<=N,M<=8
    对于100%的数据,保证 T<=10,1<=N,M<=40,所有数为正整数且小于1000000000

    Source

    这道题一看到,还真没直接想到网络流,看了看每次必须找相邻两个点,偶然想到国际象棋,于是黑白染色;
    于是统计出wnum,bnum,wsum,bsum(染成White的格子数,和初始的总数,及染成Black的格子数和初始总数)
    二分最后的结果X(x为满足所有格子都一样时的格子中的数),所以可以得到下面的一个关系式:

             X * wnum - wsum = X * bnum - bsum
        ==>  X * bnum - X * wnum = bsum - wsum
        ==>  X = (bsum - wsum)/(bnum - wnum)
    

    每次相邻两个+1可知,每次必然满足wsum+1,bsum+1;
    所以我们得到 当 bnum==wnum 时,如果满足bsum!=wsum 则无解
    当 bsum==wsum 时,如果x成立,则任何>=x的数都成立,所以二分X即可
    当 bnum!=wnum 时,发现至多有一个解,所以解得X,判断是否符合即可

    建图:
    超级源S向每个白点连边,边权为X-white【i】;
    每个白点向相邻的黑点连边,边权为INF;
    每个黑点向超级汇T连边,边权为X-black【i】;
    (X为二分出的值,white【】,black【】表示初始值)
    用tot记录差值,判断最大流是否满足即可

    值得注意的是这个题的 时间限制,以及long long。

    code:

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    using namespace std;
    #define maxl (1LL<<50)
    #define zb(x,y) (x-1)*m+y
    int dis[2005];
    struct data{
        int next,to;
        long long v;
    }edge[10005];
    int cnt=1,head[2005]={0};
    int q[2005],h,t;
    int jz[50][50]={0};
    int cur[2005];
    int n,m,tim;
    int wnum,bnum;
    long long wsum,bsum;
    int num;
    int mx=0;
    long long tot=0;
    bool zt[50][50];
    int move[4][2]={{1,0},{-1,0},{0,1},{0,-1}};
    
    void add(int u,int v,long long w)
    {
        cnt++;
        edge[cnt].next=head[u];
        head[u]=cnt;
        edge[cnt].to=v;
        edge[cnt].v=w;
    }
    
    void insert(int u,int v,long long w)
    {
        add(u,v,w);add(v,u,0);  
    }
    
    int read()
    {
        int x=0,f=1;char ch=getchar();
        while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
        while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
        return x*f;
    }
    
    void init()
    { 
        n=read(); m=read();
        for (int i=1; i<=n; i++)
            for (int j=1; j<=m; j++)
                {
                    jz[i][j]=read();
                    zt[i][j]=(i+j)&1;
                    mx=max(mx,jz[i][j]);
                }
        num=n*m+1;
        for (int i=1; i<=n; i++)
            for (int j=1; j<=m; j++)
                if (zt[i][j]) {wnum++;wsum+=jz[i][j];}
                    else {bnum++;bsum+=jz[i][j];}
    }
    
    void make(long long mv)
    {
        cnt=1;memset(head,0,sizeof(head));
        for (int i=1; i<=n; i++)
            for (int j=1; j<=m; j++)
                if (zt[i][j]) 
                {
                    insert(0,zb(i,j),mv-jz[i][j]);tot+=mv-jz[i][j];
                    for (int k=0; k<4; k++)
                        {
                            int x=i+move[k][0],y=j+move[k][1];
                            if (x>0 && x<=n && y>0 && y<=m)
                                insert(zb(i,j),zb(x,y),maxl);
                        }
                }
                else  insert(zb(i,j),num,mv-jz[i][j]);
    }
    
    bool bfs()
    {
        memset(dis,-1,sizeof(dis));
        q[1]=0; dis[0]=1;
        h=0;t=1;
        while (h<t)  
            {
                int j=q[++h],i=head[j];
                while (i)
                    {
                        if (edge[i].v>0 && dis[edge[i].to]<0)
                            {
                                dis[edge[i].to]=dis[j]+1;
                                q[++t]=edge[i].to;
                            }
                        i=edge[i].next;
                    }
            }
        if (dis[num]>0)
            return true;
        else
            return false;
    }
    
    long long dfs(int loc,long long low)
    {
        if(loc==num)return low;
        long long flow,cost=0;
        for(int i=cur[loc];i;i=edge[i].next)
            if(dis[edge[i].to]==dis[loc]+1)
                {
                    flow=dfs(edge[i].to,min(low-cost,edge[i].v));
                    edge[i].v-=flow;edge[i^1].v+=flow;
                    if(edge[i].v) cur[loc]=i;
                    cost+=flow;if(cost==low)return low;
                }
        if(!cost)dis[loc]=-1;
        return cost;
    }
    
    long long dinic()
    {
        long long temp=0;
        while (bfs())
            {
               for (int i=0; i<=num; i++) cur[i]=head[i];
               temp+=dfs(0,maxl);
            }
        return temp;
    }
    
    bool check(long long ans)
    {
        tot=0;
        make(ans);
        long long temp=dinic();
        if (temp==tot) return 1;
        return 0;   
    }
    
    int main()
    {
        tim=read();
        while (tim--)
            {
                wnum=bnum=0;wsum=bsum=0;mx=0;
                init();
                if (wnum==bnum)
                    {
                        if (wsum!=bsum) {puts("-1");continue;}
                        long long left=mx;
                        long long right=maxl;
                        while (left<=right)
                            {
                                long long mid=(left+right)/2;
                                if (check(mid))   right=mid-1;
                                        else    left=mid+1;
                            }
                        printf("%lld
    ",left*wnum-wsum);
                    }
                else
                    {
                        long long x=(bsum-wsum)/(bnum-wnum);
                        if (x>=mx) 
                            {
                                if (check(x)) {printf("%lld
    ",(x*wnum)-wsum);continue;}
                                            else puts("-1");
                            }
                        else puts("-1");                                       
                    }
            }
        return 0;  
    }
  • 相关阅读:
    Python升级3.6 强力Django+Xadmin打造在线教育平台
    第六模块:WEB框架开发 第1章·Django框架开发1~50
    阿里云主机(ECS)与CentOS7实战
    Django入门与实战
    第五模块:WEB开发基础 第2章·JavaScript基础
    第五模块:WEB开发基础 第1章·HTML&CSS基础
    第四模块:网络编程进阶&数据库开发 第2章·MySQL数据库开发
    阿里云ECS云服务器CentOS7.4下安装MySQL5.7.13、JDK1.7.80、Mycat1.6.5、Redis3.2.10、Nginx1.14.0以及Tomcat7.0.72
    《百词斩·象形9000》第一册(上) 符号Symbol 1
    第三模块:面向对象&网络编程基础 第2章 网络编程
  • 原文地址:https://www.cnblogs.com/DaD3zZ-Beyonder/p/5346227.html
Copyright © 2011-2022 走看看