CQOI2012 交换棋子

现在艹道水题都要半小时+=感觉整个人都不好了

把点拆掉就可以了=因为次数限制在格子上

又因为走进走出要2次直接÷2=想想头和尾只踩了一次所以除以2前先+1就好了

#include <bits/stdc++.h>
#define rep(j,k,l) for (int j=k;j<=l;++j)
#define K 22
#define N 805
#define M 50005

using namespace std;
int to[M],ne[M],rest[M],cost[M],st[N],a[K][K],b[K][K],c[K][K];
int dis[N],f[N],que[N],used[N],last[N],road[N];
int n,m,cnt=1,ct1,ct2,head,tail,ans,fee;

void add(int k,int l,int o,int p){
	
	to[++cnt]=l;
	ne[cnt]=st[k];
	st[k]=cnt;
	rest[cnt]=o;
	cost[cnt]=p;
	
}

bool Spfa(){
	
	rep(i,0,n) dis[i]=100000,f[i]=0;
	f[0]=1;dis[0]=0;head=0;tail=1;que[1]=0;used[0]=1;
	while (head!=tail){
		
		head=(head+1)%N;
		int x=que[head];
		used[x]=0;
		for (int i=st[x];i;i=ne[i])
			if (rest[i]&&dis[to[i]]>dis[x]+cost[i]){
				
				dis[to[i]]=dis[x]+cost[i];
				f[to[i]]=1;
				road[to[i]]=i;
				last[to[i]]=x;
				if (!used[to[i]]){
					
					tail=(tail+1)%N;
					que[tail]=to[i];
					used[to[i]]=1;
					
				}
				
			}
		
	}
	return f[n];
	
}

void rset(int k){
	
	if (k!=0) rset(last[k]);
	rest[road[k]]--;
	rest[road[k]^1]++;
	
}

int main(){
	
	scanf("%d%d",&n,&m);
	rep(i,1,n) rep(j,1,m){
		
		char ch=getchar();
		while (ch<48||ch>57) ch=getchar();
		a[i][j]=ch-48;
		if (a[i][j]){
			
			c[i][j]++;
			add(0,(i-1)*m+j,1,0);
			add((i-1)*m+j,0,0,0);
			ct1++;
			
		}
		
	}
	rep(i,1,n) rep(j,1,m){
		
		char ch=getchar();
		while (ch<48||ch>57) ch=getchar();
		b[i][j]=ch-48;
		if (b[i][j]){
			
			c[i][j]++;
			add((i-1)*m+j+n*m,n*m*2+1,1,0);
			add(n*m*2+1,(i-1)*m+j+n*m,0,0);
			ct2++;
			
		}
		
	}
	if (ct1!=ct2){
		
		printf("-1\n");
		return 0;
		
	}
	rep(i,1,n) rep(j,1,m){
		
		char ch=getchar();
		while (ch<48||ch>57) ch=getchar();
		c[i][j]=(c[i][j]+ch-48)/2;
		add((i-1)*m+j,(i-1)*m+j+n*m,c[i][j],0);
		add((i-1)*m+j+n*m,(i-1)*m+j,0,0);
		if (i>1){
			
			add((i-1)*m+j+n*m,(i-2)*m+j,100000,1);
			add((i-2)*m+j,(i-1)*m+j+n*m,0,-1);
			
		}
		if (j>1){
			
			add((i-1)*m+j+n*m,(i-1)*m+j-1,100000,1);
			add((i-1)*m+j-1,(i-1)*m+j+n*m,0,-1);
			
		}
		if (i<n){
			
			add((i-1)*m+j+n*m,i*m+j,100000,1);
			add(i*m+j,(i-1)*m+j+n*m,0,-1);
			
		}
		if (j<m){
			
			add((i-1)*m+j+n*m,(i-1)*m+j+1,100000,1);
			add((i-1)*m+j+1,(i-1)*m+j+n*m,0,-1);
			
		}
		if (i>1&&j>1){
			
			add((i-1)*m+j+n*m,(i-2)*m+j-1,100000,1);
			add((i-2)*m+j-1,(i-1)*m+j+n*m,0,-1);
			
		}
		if (i<n&&j>1){
			
			add((i-1)*m+j+n*m,i*m+j-1,100000,1);
			add(i*m+j-1,(i-1)*m+j+n*m,0,-1);
			
		}
		if (i>1&&j<m){
			
			add((i-1)*m+j+n*m,(i-2)*m+j+1,100000,1);
			add((i-2)*m+j+1,(i-1)*m+j+n*m,0,-1);
			
		}
		if (i<n&&j<m){
			
			add((i-1)*m+j+n*m,i*m+j+1,100000,1);
			add(i*m+j+1,(i-1)*m+j+n*m,0,-1);
			
		}
		
	}
	n=n*m*2+1;
	while (Spfa()){
		
		ans+=f[n];
		fee+=f[n]*dis[n];
		rset(n);
		
	}
	if (ans!=ct1) printf("-1\n");
	else printf("%d\n",fee);
	return 0;
	
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值