您的位置:首页 > 理论基础 > 计算机网络

bzoj 2756: [SCOI2012]奇怪的游戏(网络流+二分)

2016-08-26 15:05 375 查看

2756: [SCOI2012]奇怪的游戏

Time Limit: 40 Sec  Memory Limit: 128 MB
Submit: 2959  Solved: 807

[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 

 

Source



[Submit][Status][Discuss]

题解:二分+网络流判定

设最后所有格子里的数为k,可以列出式子num_odd*k-sum_odd=num_even*k-sum_even

如果n*m是奇数,那么可以解出k=(sum_odd-sum_even)/(num_odd-num_even);

如果是偶数的话,我们可以二分。因为如果是偶数的话我们对于整个棋盘进行棋盘覆盖,就可以使所有的数都+1.所有满足二分的性质。

考虑建图判定。

 对棋盘进行黑白染色。

S->黑点

白点->T

相邻点之间连inf。然后黑白分别到源汇连val-K。

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
#include<queue>
#define N 50
#define M 20000
#define LL long long
#define inf 2000000000
using namespace std;
int n,m,t,cnt;
int tot,point[M],next[M],v[M],deep[M],num[M],cur[M];
int map

,pos

,last[M],num1,num2;
LL sum1,sum2,remain[M],h

;
int xx[10]={0,-1,0,1},yy[10]={-1,0,1,0};
void add(int x,int y,LL z)
{
tot++; next[tot]=point[x]; point[x]=tot; v[tot]=y; remain[tot]=z;
tot++; next[tot]=point[y]; point[y]=tot; v[tot]=x; remain[tot]=0;
//cout<<x<<" "<<y<<" "<<z<<endl;
}
LL addflow(int s,int t)
{
int now=t; LL ans=1e18;
while (now!=s)
{
ans=min(ans,remain[last[now]]);
now=v[last[now]^1];
}
now=t;
while (now!=s)
{
remain[last[now]]-=ans;
remain[last[now]^1]+=ans;
now=v[last[now]^1];
}
return ans;
}
void bfs(int s,int t)
{
queue<int> p;
for (int i=s;i<=t;i++) deep[i]=t;
deep[t]=0; p.push(t);
while (!p.empty())
{
int now=p.front(); p.pop();
for (int i=point[now];i!=-1;i=next[i])
if (deep[v[i]]==t&&remain[i^1])
deep[v[i]]=deep[now]+1,p.push(v[i]);
}
}
LL isap(int s,int t)
{
bfs(s,t);
for (int i=s;i<=t;i++) cur[i]=point[i];
for (int i=s;i<=t;i++) num[deep[i]]++;
int now=s; LL ans=0;
while (deep[s]<t)
{
if (now==t)
{
ans+=addflow(s,t);
now=s;
}
bool f=false;
for (int i=cur[now];i!=-1;i=next[i])
if (deep[now]==deep[v[i]]+1&&remain[i])
{
cur[now]=i;
last[v[i]]=i;
f=true;
now=v[i];
break;
}
if (!f)
{
int minn=t;
for (int i=point[now];i!=-1;i=next[i])
if (remain[i])  minn=min(minn,deep[v[i]]);
if (!--num[deep[now]]) break;
deep[now]=minn+1;
num[deep[now]]++;
cur[now]=point[now];
if (now!=s)
now=v[last[now]^1];
}
}
return ans;
}
bool pd(LL height)
{
tot=-1;
memset(point,-1,sizeof(point));
memset(next,-1,sizeof(next));
memset(num,0,sizeof(num));
int s=1; int t=cnt+1;
LL sum=0,sum1=0;
for (int i=1;i<=n;i++)
for (int j=1;j<=m;j++)
{
if (map[i][j])
{
add(s,pos[i][j],height-h[i][j]);
sum+=height-h[i][j];
for (int k=0;k<4;k++)
{
int nowx=i+xx[k];
int nowy=j+yy[k];
if (nowx>0&&nowy>0&&nowx<=n&&nowy<=m)
add(pos[i][j],pos[nowx][nowy],1e18);
}
}
else add(pos[i][j],t,height-h[i][j]),sum1+=height-h[i][j];
}
LL tt=isap(s,t);
if (tt==sum&&tt==sum1) return true;
else return false;
}
int main()
{
scanf("%d",&t);
for (int T=1;T<=t;T++)
{
scanf("%d%d",&n,&m);
tot=-1; sum1=0; sum2=0; LL maxn=0; cnt=1;
num1=0; num2=0;
memset(point,-1,sizeof(point));
memset(next,-1,sizeof(next));
memset(num,0,sizeof(num));
memset(map,0,sizeof(map));
for (int i=1;i<=n;i++)
for (int j=1;j<=m;j++)
scanf("%lld",&h[i][j]),maxn=max(maxn,h[i][j]);
for (int i=1;i<=n;i++)
for (int j=1;j<=m;j++)
{
pos[i][j]=++cnt;
if (i%2)
{
if (j%2)  map[i][j]=1,sum1+=h[i][j],num1++;
else sum2+=h[i][j],num2++;
}
else if (j%2==0) map[i][j]=1,sum1+=h[i][j],num1++;
else sum2+=h[i][j],num2++;
}
if ((n*m)%2)
{
LL t=(sum1-sum2)/(num1-num2);
if (!pd(t)||t<maxn)  printf("-1\n");
else printf("%lld\n",(t*n*m-sum1-sum2)/2);
continue;
}
LL l=maxn; LL r=inf;
LL ans=inf;
while (l<=r)
{
LL mid=(l+r)/2;
if (pd(mid))  ans=min(ans,mid),r=mid-1;
else l=mid+1;
}
if (ans==inf) printf("-1\n");
else printf("%lld\n",(ans*n*m-sum1-sum2)/2);
}
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: