UVA - 563 Crimewave 经典逃脱问题

题目大意:在一个S*A的矩形里面有B个银行,要求从这些银行出发,然后不重复的走到边界,如果可以的话,输出possible,不行的话输出not possible

解题思路:和UVA10330相似,把点拆成边,权值设置为1,然后设置一个超级源点和一个超级汇点,超级源点和银行的点连接起来,边界和超级汇点连接起来即可,再DFS的时候要加一个判断,不然就会TLE,如果i == -1 ,就将d[cur]设置成-1,表示无法走通了,因为点是很多的

#include<cstdio>
#include<cstring>
#define INF 0x3f3f3f3f
#define maxn 7200
#define maxm 1000000
int S,A,B,e;
int head[maxn],next[maxm],u[maxm],v[maxm],q[maxm],f[maxm],d[maxm];
int s[maxm];
void add(int a,int b,int w) {

	u[e] = a;
	v[e] = b;
	f[e] = w;
	next[e] = head[a];
	head[a] = e;
	e++;

}

void init() {
	memset(head,-1,sizeof(head));
	e = 0;
	int x,y,z1,z2;
	for(int i = 1; i <= A; i++) {
		z1 = A + i;
		z2 = A * S + i;
		add(2*z1^1,1,1);
		add(1,2*z1^1,0);
		add(2*z2^1,1,1);
		add(1,2*z2^1,0);		
	}

	for(int i = 1; i <= S; i++) {
		z1 = i * A + 1;
		z2 = A * i + A;
		add(2*z1^1,1,1);
		add(1,2*z1^1,0);
		add(2*z2^1,1,1);
		add(1,2*z2^1,0);		
	}
	int newz;
	for(int i = 1; i <= S; i++)
		for(int j = 1; j <= A; j++) {
			z1 = i * A + j;
			add(2*z1,2*z1^1,1);
			add(2*z1^1,2*z1,0);	
			if(i + 1 <= S) {
				newz = (i + 1) * A + j;
				add(2*z1^1,2*newz,1);
				add(2*newz,2*z1^1,0);
				add(2*newz^1,2*z1,1);
				add(2*z1,2*newz^1,0);
			}
			if(j + 1 <= A) {
				newz = i * A + j + 1;	
				add(2*z1^1,2*newz,1);
				add(2*newz,2*z1^1,0);
				add(2*newz^1,2*z1,1);
				add(2*z1,2*newz^1,0);
			}	
		}
	for(int i = 0; i < B; i++) {
		scanf("%d%d",&x,&y);
		z1 = x * A + y;
		add(0,2*z1,1);
		add(2*z1,0,0);	
	}
}

int bfs() {
	memset(d,-1,sizeof(d));
	int rear = 0;
	d[0] = 0;
	q[rear++] = 0;
	
	for(int i = 0; i < rear; i++)
		for(int j = head[q[i]]; j != -1; j = next[j])
			if(d[v[j]] == -1 && f[j]) {
				d[v[j]] = d[q[i]] + 1;
				if(v[j] == 1)
					return 1;
				q[rear++] = v[j];
			}
	return 0;
}

int dfs(int cur, int a) {
	if(cur  == 1)
		return a;
	int i ;
	for(i = head[cur]; i != -1; i = next[i]) 
		if(d[v[i]] == d[cur] + 1 && f[i]) {
			if(int t = dfs(v[i],a < f[i] ? a: f[i])) {
				f[i] -= t;
				f[i^1] += t;
				return t;	
			}	
		}
	if(i == -1)
		d[cur] = -1;
	return 0;
}

int EK() {
	int ans = 0, t;
	while(bfs()) {
		while(t = dfs(0,INF))	
			ans += t;
	}
	return ans;
}

int main() {
	int test;
	scanf("%d",&test);
	while(test--) {
		scanf("%d%d%d",&S,&A,&B);
		init();	
		if(EK() == B)
			printf("possible\n");
		else
			printf("not possible\n");
	}
	return 0;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值