• 奇怪的游戏


    奇怪的游戏

    题目描述

     

    Blinker最近喜欢上一个奇怪的游戏。

    这个游戏在一个N*M的棋盘上玩,每个格子有一个数。每次Blinker会选择两个相邻的格子,并使这两个数都加上1。

    现在Blinker想知道最少多少次能使棋盘上的数都变成同一个数,如果永远不能变成同一个数则输出-1。

     

     

    输入

     

    输入的第一行是一个整数T,表示输入数据有T轮游戏组成。

    每轮游戏的第一行有两个整数N和M,  分别代表棋盘的行数和列数。

    接下来有N行,每行M个数。

     

     

    输出

     

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

     

     

    样例输入

    2 
    2 2
    1 2
    2 3
    3 3
    1 2 3
    2 3 4
    4 3 2

    样例输出

    2 
    -1 

    提示

     

    【数据范围】

    对于30%的数据,保证  T<=10,1<=N,M<=8

    对于100%的数据,保证  T<=10,1<=N,M<=40,所有数为正整数且小于1000000000 

     

    solution

    对棋盘进行黑白染色
    设黑格个数为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)

    转自http://hzwer.com/5992.html

    黄学长写的真好orz

    #include<cstdio>
    #include<iostream>
    #include<cstdlib>
    #include<cstring>
    #include<algorithm>
    #include<cmath>
    #include<queue>
    #define inf 1e15
    #define maxn 10005
    using namespace std;
    int Te,n,m,num1,num2;
    int head[maxn],cur[maxn],S,T,tot,flag[maxn];
    long long s[45][45],sum1,sum2,Max,l,r,d[maxn];
    struct node{
        int v,nex;
        long long cap;
    }e[200005];
    int get(int i,int j){
        return (i-1)*m+j;
    }
    int dx[4]={0,1,0,-1};
    int dy[4]={1,0,-1,0};
    bool can(int i,int j){
        if(i>0&&i<=n&&j>0&&j<=m)return 1;
        return 0;
    }
    void lj(int t1,int t2,long long t3){
        e[++tot].v=t2;e[tot].cap=t3;e[tot].nex=head[t1];head[t1]=tot;
        e[++tot].v=t1;e[tot].cap=0;e[tot].nex=head[t2];head[t2]=tot;
    }
    bool BFS(){
        for(int i=1;i<=T;i++)d[i]=inf;
        queue<int>q;q.push(S);d[S]=0;
        while(!q.empty()){
            int x=q.front();q.pop();cur[x]=head[x];
            for(int i=head[x];i;i=e[i].nex){
                if(d[e[i].v]>d[x]+1&&e[i].cap){
                    d[e[i].v]=d[x]+1;
                    if(!flag[e[i].v]){
                        q.push(e[i].v);flag[e[i].v]=1;
                    }
                }
            }
            flag[x]=0;
        }
        return d[T]!=inf;
    }
    long long lian(int k,long long a){
        if(k==T||!a)return a;
        long long f,flow=0;
        for(int &i=cur[k];i;i=e[i].nex){
            if(d[e[i].v]==d[k]+1&&(f=lian(e[i].v,min(e[i].cap,a)))>0){
                flow+=f;a-=f;
                e[i].cap-=f;e[i^1].cap+=f;
                if(!a)break;
            }
        }
        return flow;
    }
    bool pd(long long mid){
        S=10000,T=10001;tot=1;
        long long cnt=0,ans=0;
        for(int i=1;i<=T;i++)head[i]=0;
        for(int i=1;i<=n;i++){
            for(int j=1;j<=m;j++){
                int now=get(i,j);
                if(mid<s[i][j])return 0;
                if((i+j)&1){
                    lj(S,now,mid-s[i][j]);cnt+=mid-s[i][j];
                    for(int t=0;t<4;t++){
                        int tx=i+dx[t],ty=j+dy[t];
                        if(can(tx,ty))lj(now,get(tx,ty),inf);
                    }
                }
                else {
                    lj(now,T,mid-s[i][j]);
                }
            }
        }
        while(BFS())ans+=lian(S,inf);
        return ans==cnt;
    }
    int main(){
        cin>>Te;
        while(Te--){
            scanf("%d%d",&n,&m);
            num1=num2=0;sum1=sum2=0;Max=0;
            for(int i=1;i<=n;i++){
                for(int j=1;j<=m;j++){
                    scanf("%lld",&s[i][j]);
                    Max=max(Max,s[i][j]);
                    if((i+j)&1){
                        num1++,sum1+=s[i][j];
                    }
                    else num2++,sum2+=s[i][j];
                }
            }
            if(num1==num2){
                l=Max,r=inf;
                while(l<r){
                    int mid=l+r>>1;
                    if(pd(mid))r=mid;
                    else l=mid+1;
                }
                cout<<num1*r-sum1<<endl;
            }
            else {
                long long x=(sum1-sum2)/(num1-num2);
                //cout<<x<<sum1<<' '<<sum2<<' '<<num1<<' '<<num2<<endl;
                if(pd(x))cout<<num1*x-sum1<<endl;
                else puts("-1");
            }
        }
        return 0;
    }
  • 相关阅读:
    【原创游戏】合金弹头S——Unity制作的同人游戏
    【原创游戏】Extreme Ball——虐心小游戏
    【原创游戏】迷踪失路——恐怖风格的第一人称迷宫游戏
    生成二维码工具类及使用
    使用base64对图片的加密解密
    将图片转换成二进制, (用到 输入流,输出流)
    图片的缩放(放大缩小)
    逻辑推理
    应该在别人恐惧时贪婪吗?
    SQL 2005数据类型说明
  • 原文地址:https://www.cnblogs.com/liankewei/p/10358869.html
Copyright © 2020-2023  润新知