• [SCOI2012][BZOJ2756] 奇怪的游戏


    2756: [SCOI2012]奇怪的游戏

    Time Limit: 40 Sec  Memory Limit: 128 MB
    Submit: 1970  Solved: 515
    [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 

     

    http://cxjyxx.me/?p=223

    cxjyxx_me:

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

    对棋盘进行黑白染色
    设黑格个数为num1 数值和为sum1
    设白格个数为num1 数值和为sum1

    设最后都变为x

    num1 * x – sum1 = num2 * x – sum2
    x = (sum1 – sum2) / (num1 – num2)
    当num1 ≠ num2时 可以解出 x 再用网络流check即可

    对于num1 = num2时 可以发现 对于一个合法的x k>=x都是一个合法的解
    因为num1 = num2 => (num1 + num2) % 2 == 0 可以构造一层的满覆盖
    所以可以二分x 然后用网络流check

    建图:
    如果点k为白
    建边(s, k, x – v[k])
    如果为黑
    建边(k, t, x – v[k])
    对相邻点u、v (u为白)
    建边 (u, v, inf)

    PS:昨晚研究了下二分图的问题,这也是第一道染色建图的题目,不过真心没有调出来……不知道哪里出了问题,不想继续浪费时间。

    未AC代码:

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<cstdlib>
    #include<algorithm>
    #include<cmath>
    #include<vector>
    #include<queue>
    #define ll long long
    #define INF (1LL<<50)
    using namespace std;
    int S,T,t,n,m,edge=1,dis[2005],q[2005],head[2005],list[30000],next[30000];
    ll mx,a[50][50],num1,num2,sum1,sum2,cnt,num[50][50],key[30000];
    int dx[4]={-1,0,1,0};
    int dy[4]={0,-1,0,1};
    void insert(int x,int y,ll z)
    {
        next[++edge]=head[x];
        head[x]=edge;
        list[edge]=y;
        key[edge]=z;
    }
    void build_paint()
    {
        sum1=0;sum2=0;
        cnt=0;
        for (int i=1;i<=n;i++)
            for (int j=1+(i%2==0);j<=m;j+=2)
            {
                num[i][j]=++cnt;
                sum1+=a[i][j];
            }
        num1=cnt;
        for (int i=1;i<=n;i++)
            for (int j=1+(i%2==1);j<=m;j+=2)
            {
                num[i][j]=++cnt;
                sum2+=a[i][j];
            }
        num2=cnt-num1;    
    }
    bool BFS()
    {
        memset(dis,0xff,sizeof(dis));
        dis[0]=1; q[1]=0;
        int t=0,w=1,x;
        while (t<w)
        {
            x=q[++t];
            for (int i=head[x];i;i=next[i])
                if (key[i]&&dis[list[i]]==-1)
                {
                    dis[list[i]]=dis[x]+1;
                    q[++w]=list[i];
                }
        }
        return dis[T]!=-1;
    }
    ll find(int x,ll flow)
    {
        if (x==T) return flow;
        ll used=0,w;
        for (int i=head[x];i;i=next[i])
            if (key[i]&&dis[list[i]]==dis[x]+1)
            {
                w=find(list[i],min(key[i],flow-used));
                key[i]-=w;
                key[i^1]+=w;
                used+=w;
                if (used==flow) return flow;
            }
        if (!used) dis[x]=-1;
        return used;
    }
    ll dinic()
    {
        ll ans=0;
        while (BFS()) ans+=find(S,INF);
        return ans;
    }
    bool check(ll x)
    {
        memset(head,0,sizeof(head));
        ll tot=0;
        int xx,yy;
        edge=1;
        for (int i=1;i<=n;i++)
            for (int j=1+(i%2==0);j<=m;j+=2)
            {
                tot+=x-a[i][j];
                insert(S,num[i][j],x-a[i][j]);
                insert(num[i][j],S,0);
                for (int k=0;k<4;k++)
                {
                    xx=i+dx[k];
                    yy=j+dy[k];
                    if (xx<1||xx>n||yy<1||yy>m) continue;
                    insert(num[i][j],num[xx][yy],INF);
                    insert(num[xx][yy],num[i][j],0);
                }
            }
        for (int i=1;i<=n;i++)
            for (int j=1+(i%2==1);j<=m;j+=2)
            {
                insert(num[i][j],T,x-a[i][j]);
                insert(T,num[i][j],0);
            }
        if (dinic()==tot) return 1; return 0;
    }
    int main()
    {
        freopen("game.in","r",stdin);
        freopen("game.out","w",stdout);
        
        scanf("%d",&t);
        while (t--)
        {
            scanf("%d%d",&n,&m);
            S=0;T=n*m+1;
            mx=0;
            for (int i=1;i<=n;i++)
                for (int j=1;j<=m;j++)
                {
                    scanf("%lld",&a[i][j]);
                    mx=max(mx,a[i][j]);
                }
            build_paint();
            if (num1!=num2)
            {
                ll x=(sum1-sum2)/(num1-num2);
                if (x>=mx)
                    if (check(x))
                    {
                        printf("%lld
    ",x*num2-sum2);
                        continue;
                    }
                printf("-1
    ");
            }
            else
            {
                ll l=mx,r=INF;
                while (l<=r)
                {
                    ll mid=(l+r)>>1;
                    if (check(mid)) r=mid-1; else l=mid+1;
                }
                printf("%lld
    ",num2*l-sum2);
            }
        }
        return 0;
    }

    想看AC代码的出门左拐hzwer.com

  • 相关阅读:
    Y460/Y470 Nvidia optirum solution : switch off the nvidia card and solve screen flash problem
    matlab中提示错误使用* BLAS loading error解决方法
    学习笔记 第十四周 第一篇
    学习笔记 第十三周 第一篇
    学习笔记 第十二周 第一篇
    学习笔记 第十一周 第一篇
    学习笔记 第十周 第一篇
    学习笔记 第九周 第一篇
    学习笔记 第八周 第二篇(修改版)
    学习笔记 第八周 第二篇
  • 原文地址:https://www.cnblogs.com/ws-fqk/p/4664396.html
Copyright © 2020-2023  润新知