码迷,mamicode.com
首页 > 其他好文 > 详细

BZOJ2756: [SCOI2012]奇怪的游戏

时间:2018-02-28 14:08:19      阅读:175      评论:0      收藏:0      [点我收藏+]

标签:data   ast   using   namespace   ret   php   数据   type   接下来   

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 

 
 
这TM哪是人做的题根本想不出来
黑白染色,然后不会
没题解会死系列
 
首先有两种情况:
设黑棋子出现次数为B,权值和为Black,白色为W,和为White
 
如果B==W:
如果Black!=white,那么就无解。至于怎么解释,我不是很会说,
应该就似棋盘问题的东西(挖掉对角两个格子,就不能用长度为2宽度为1的骨牌完全覆盖)
那么如果相等,一定有解,那么就二分枚举ans,设ans为最终每个格子最终的值,
然后  ST->Black   ans-a[i][j]
    Black->White  INF
         White->ED   ans-a[i][j]
 
如果B!=W:
那么就推柿子,验证答案即可
 
黄学长博客:传送门
 
代码如下:
#include<cmath>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<algorithm>
using namespace std;
typedef long long ll;
struct node{
    int x,y,next,other;
    ll c;
}a[71000];int len,last[71000];

const ll INF=(1ll<<60);
void ins(int x,int y,ll c)
{
    int k1,k2;
    k1=++len;
    a[len].x=x;a[len].y=y;a[len].c=c;
    a[len].next=last[x];last[x]=len;
    
    k2=++len;
    a[len].x=y;a[len].y=x;a[len].c=0;
    a[len].next=last[y];last[y]=len;
    
    a[k1].other=k2;
    a[k2].other=k1;
}
int st,ed,h[81000];
int head,tail,list[21000];
bool bt_h()
{
    memset(h,0,sizeof(h));h[st]=1;
    list[1]=st;head=1;tail=2;
    while(head!=tail)
    {
        int x=list[head];
        for(int k=last[x];k;k=a[k].next)
        {
            int y=a[k].y;
            if(h[y]==0&&a[k].c>0)
            {
                h[y]=h[x]+1;
                list[tail++]=y;
            }
        }
        head++;
    }
    if(h[ed]>0)return true;
    return false;
}
/*
3 3
10 9 8
1 4 1
5 3 7
*/
ll findflow(int x,ll f)
{
    if(x==ed)return f;
    ll s=0,t;
    for(int k=last[x];k;k=a[k].next)
    {
        int y=a[k].y;
        if(h[y]==h[x]+1&&a[k].c>0&&s<f)
        {
            s+=(t=findflow(y,min(a[k].c,f-s)));
            a[k].c-=t;a[a[k].other].c+=t;
        }
    }
    if(s==0)h[x]=0;
    return s;
}
int f[61][61];
int n,m;
int p[61][61],cnt;
ll c[61][61];
ll black,white,b,w;
bool check(ll x)
{
    ll tot=0;
    len=0;memset(last,0,sizeof(last));
    for(int i=1;i<=n;i++)
        for(int j=1;j<=m;j++)
        {
            if(f[i][j]==1)
            {
                ins(st,p[i][j],x-c[i][j]);tot+=x-c[i][j];
                if(i>1)ins(p[i][j],p[i-1][j],INF);
                if(j>1)ins(p[i][j],p[i][j-1],INF);
                if(i<n)ins(p[i][j],p[i+1][j],INF);
                if(j<m)ins(p[i][j],p[i][j+1],INF);
            }
            else ins(p[i][j],ed,x-c[i][j]);
            
        }
    ll sum=0;
    while(bt_h()==true)
        sum+=findflow(st,INF);
    if(sum==tot)return true;
    return false;
}
int main()
{
    int T;ll mx;
    scanf("%d",&T);
    while(T--)
    {
        cnt=0;mx=0;
        scanf("%d%d",&n,&m);st=0,ed=n*m+1;
        for(int i=1;i<=n;i++)
            for(int j=1;j<=m;j++)
                scanf("%lld",&c[i][j]),p[i][j]=++cnt,mx=max(mx,c[i][j]);
        black=white=b=w=0;
        for(int i=1;i<=n;i++)
            for(int j=1;j<=m;j++)
            {
                f[i][j]=(i+j)&1;
                if(f[i][j]==1)black++,b+=c[i][j];
                else white++,w+=c[i][j];
            }
        if(black==white)
        {
            if(b!=w)printf("-1\n");
            else
            {
                ll l=mx,r=INF;
                while(l<=r)
                {
                    ll mid=(l+r)/2;
                    if(check(mid)==true)r=mid-1;
                    else l=mid+1;
                }
                printf("%lld\n",l*black-b);
            }
        }
        else
        {
            ll ans=(w-b)/(white-black);
            if(check(ans)==true){
                if(ans>=mx)
                    printf("%lld\n",ans*black-b);}
            else printf("-1\n");
        }
    }
    return 0;
}

by_lmy

BZOJ2756: [SCOI2012]奇怪的游戏

标签:data   ast   using   namespace   ret   php   数据   type   接下来   

原文地址:https://www.cnblogs.com/MT-LI/p/8483017.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!