BZOJ P2756[SCOI2012]奇怪的游戏

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#define inf (1LL<<50)
#define p(x,y) (x-1)*m+y
using namespace std;
const int xx[4]={0,0,1,-1};
const int yy[4]={1,-1,0,0};
long long s0,s1;
int c0,c1,test,n,m,cnt,S,T;
int a[45][45],last[2005],h[2005],q[2005],cur[2005];
bool color[45][45];
struct edge{
    int to,next;
	long long v;
}e[20005];
void insert(int u,int v,long long w){
    e[++cnt].to=v;e[cnt].next=last[u];last[u]=cnt;e[cnt].v=w;
    e[++cnt].to=u;e[cnt].next=last[v];last[v]=cnt;e[cnt].v=0;
}
bool bfs(){
    int head=0,tail=1;
    memset(h,-1,sizeof(h));
    q[0]=S;h[S]=0;
    while(head!=tail){
        int now=q[head];head++;
        for(int i=last[now];i;i=e[i].next){
        	if(e[i].v&&h[e[i].to]==-1){
                h[e[i].to]=h[now]+1;
                q[tail++]=e[i].to;
            }
		}
    }
    return h[T]!=-1;
}
long long dfs(int x,long long f){
    if(x==T){
    	return f;
	}
    long long w,used=0;
    for(int i=cur[x];i;i=e[i].next){
    	if(h[e[i].to]==h[x]+1){
            w=dfs(e[i].to,min(f-used,e[i].v));
            e[i].v-=w;e[i^1].v+=w;
            if(e[i].v){
            	cur[x]=i;
			}
            used+=w;
			if(used==f){
            	return f;
			}
        }
	}
    if(!used){
    	h[x]=-1;
	}
    return used;
}
long long dinic(){
    long long tmp=0;
    while(bfs()){
        for(int i=S;i<=T;i++){
        	cur[i]=last[i];
		}
        tmp+=dfs(S,inf);
    }
    return tmp;
}
bool check(long long x){
    memset(last,0,sizeof(last));
    cnt=1;
	S=0;
	T=n*m+1;
    long long tot=0;
    for(int i=1;i<=n;i++){
    	for(int j=1;j<=m;j++){
        	if(color[i][j]){
                insert(S,p(i,j),x-a[i][j]);
				tot+=x-a[i][j];
                for(int k=0;k<4;k++){
                    int nowx=i+xx[k];
					int nowy=j+yy[k];
                    if(nowx<1||nowy<1||nowx>n||nowy>m){
                    	continue;
					}
                    insert(p(i,j),p(nowx,nowy),inf);
                }
            }else{
            	insert(p(i,j),T,x-a[i][j]);
			}
		}
	}  
    if(dinic()==tot){
    	return 1;
	}
    return 0;
}
int main(){
    cin>>test;
    while(test--){
        c0=c1=s0=s1=0;
        cin>>n>>m;
        int mx=0;
        for(int i=1;i<=n;i++){
        	for(int j=1;j<=m;j++){
        		cin>>a[i][j];
                color[i][j]=(i+j)&1;
                mx=max(mx,a[i][j]);
            }
		}
        for(int i=1;i<=n;i++){
        	for(int j=1;j<=m;j++){
            	if(color[i][j]){
                	s1+=a[i][j],c1++;
				}else{
                	s0+=a[i][j],c0++;
				}
			}
		} 
        if(c0!=c1){
            long long x=(s0-s1)/(c0-c1);
            if(x>=mx){
            	if(check(x)){
            		cout<<x*c1-s1<<endl;
                    continue;
                }
			}
			cout<<"-1"<<endl;
        }else{
            if(s0!=s1){
            	cout<<"-1"<<endl;
                continue;
            }
            long long l=mx,r=inf;
            while(l<=r){
                long long mid=(l+r)>>1;
                if(check(mid)){
                	r=mid-1;
				}else{
					l=mid+1;
				}
            }
            cout<<(long long)l*c1-s1<<endl;
        }
    }   
    return 0;
}
/*

in:
2
2 2
1 2
2 3
3 3
1 2 3
2 3 4
4 3 2

out:
2
-1

*/
直接二分一下最大的值,然后最大流判断就可以了
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值