zoukankan      html  css  js  c++  java
  • bzoj2756 [SCOI2012]奇怪的游戏

    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
     
    现场没有想出正解QAQ
    结论+二分网络流
    首先对所有格子黑白染色,显然每涂一次只能涂一黑一白
    假设所有黑色格子的权值之和为s1,白色格子权值之和为s2,黑色格子有d1个,白色格子有d2个
    假设我们要到达所有格子都是x的状态
    那么因为每次增加的是一黑一白,很容易列出方程式
    d1*x-s1=d2*x-s2
    x=(s1-s2)/(d1-d2)
    当d1!=d2,直接解出x,网络流判断
    当d1==d2,假设当前全是x的状态是一个可行解,那么x+1也是。
    所以可以考虑二分x,网络流判定
    /**************************************************************
        Problem: 2756
        User: zhouhebin
        Language: C++
        Result: Accepted
        Time:7096 ms
        Memory:79436 kb
    ****************************************************************/
     
    #include<cstdio>
    #include<iostream>
    #include<cstring>
    #define LL long long
    #define inf (1LL<<50)
    #define N 1610
    #define S 0 
    #define T (n*m+1)
    #define pos(x,y) (x-1)*m+y
    using namespace std;
    int mx[4]={1,0,-1,0},my[4]={0,1,0,-1};
    inline LL read()
    {
        LL 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;
    }
    int tt,n,m,cnt,Mx,s1,s2;
    LL sum1,sum2,l,r,tot,ans,QAQ;
    int a[55][55];
    struct edge{int to,next;LL v;}e[5000000];
    int head[N],q[N],h[N];
    inline void ins(int u,int v,LL w)
    {
        e[++cnt].to=v;
        e[cnt].v=w;
        e[cnt].next=head[u];
        head[u]=cnt;
    }
    inline void insert(int u,int v,LL w)
    {
        ins(u,v,w);
        ins(v,u,0);
    }
    inline bool bfs()
    {
        memset(h,-1,sizeof(h));
        int t=0,w=1;
        q[0]=S;h[S]=0;
        while (t!=w)
        {
            int now=q[t++];if (t==1605)t=0;
            for (int i=head[now];i;i=e[i].next)
                if (e[i].v&&h[e[i].to]==-1)
                {
                    h[e[i].to]=h[now]+1;
                    q[w++]=e[i].to;
                    if (w==1605)w=0;
                }
        }
        return h[T]!=-1;
    }
    inline LL dfs(int x,LL f)
    {
        if (x==T||!f)return f;
        LL w,used=0;
        for (int i=head[x];i;i=e[i].next)
            if (e[i].v&&h[e[i].to]==h[x]+1)
            {
                w=dfs(e[i].to,min(e[i].v,f-used));
                e[i].v-=w;
                e[i^1].v+=w;
                used+=w;
                if (used==f)return f;
            }
        if (!used)h[x]=-1;
        return used;
    }
    inline void dinic(){while (bfs())ans+=dfs(S,inf);}
    inline void build(LL x)
    {
        ans=0;cnt=1;tot=0;
        memset(head,0,sizeof(head));
        for (int i=1;i<=n;i++)
            for (int j=1;j<=m;j++)
                if ((i+j)&1)
                {
                    insert(S,pos(i,j),x-a[i][j]);
                    for(int k=0;k<4;k++)
                    {
                        int nx=i+mx[k],ny=j+my[k];
                        if (nx<1||ny<1||nx>n||ny>m)continue;
                        insert(pos(i,j),pos(nx,ny),inf);
                    }
                    tot+=x-a[i][j];
                }else insert(pos(i,j),T,x-a[i][j]);
    }
    inline bool jud(LL x)
    {
        build(x);
        dinic();
        return ans==tot;
    }
    inline void work()
    {
        n=read();m=read();
        sum1=sum2=s1=s2=Mx=0;
        for (int i=1;i<=n;i++)
            for (int j=1;j<=m;j++)
            {
                a[i][j]=read();
                Mx=max(Mx,a[i][j]);
                if ((i+j)&1)sum1+=a[i][j],s1++;
                else sum2+=a[i][j],s2++;
            }
        if(s1!=s2)
        {
            LL des=(sum1-sum2)/(s1-s2);
            if (des>=Mx&&jud(des))printf("%lld
    ",ans);
                else printf("-1
    ");
            return;
        }
        QAQ=inf;l=Mx;r=2000000000;
        while (l<=r)
        {
            LL mid=(l+r)>>1;
            if (jud(mid))QAQ=min(QAQ,ans),r=mid-1;
            else l=mid+1;
        }
        printf("%lld
    ",QAQ);
    }
    int main()
    {
        tt=read();
        while (tt--)work();
        return 0;
    }
    
    ——by zhber,转载请注明来源
  • 相关阅读:
    Ubuntu下官方QQ崩溃的解决
    [转]PHP函数的实现原理及性能分析
    [收藏的资料]301重定向的实现方法
    手动配置Ubuntu 指定DNS服务器地址
    C# FTP操作类
    vs2010 快捷键大全
    分享一个不错的VS插件——CodeMap
    C# 快速的批量修改重命名.net程序的命名空间(一)转 tianyaxiang
    jquery 的 ajax 程序 简单的
    winform窗体间传值
  • 原文地址:https://www.cnblogs.com/zhber/p/4216176.html
Copyright © 2011-2022 走看看