zhber
有好多做过的题没写下来,如果我还能记得就补吧

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\n",ans);
            else printf("-1\n");
        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\n",QAQ);
}
int main()
{
    tt=read();
    while (tt--)work();
    return 0;
}

 

posted on 2015-01-11 10:39  zhber  阅读(163)  评论(0编辑  收藏  举报