UVa563 Crimewave

        题意:一个s*a条线的网格,网格线的交点出是银行(共s*a个),晚上若干个银行会被抢,罪犯要逃跑到网格边界以外。为了安全起见,所有的罪犯不能经过同一个交点,问存在这样的逃跑路径吗。

        思路:最大流,把每个点拆成两个,一个用来入,一个用来出。建图源点->被抢银行入->被抢银行出->相邻银行入->...->边界->汇点。数据量有点大,不能用二维数组来存,改成vector。

#include <iostream>
#include <stdio.h>
#include <cmath>
#include <algorithm>
#include <iomanip>
#include <cstdlib>
#include <string>
#include <memory.h>
#include <vector>
#include <queue>
#include <stack>
#include <ctype.h>
#define INF 1000000000
using namespace std;


int s,a,b;

vector<int> E[5010];
vector<int> c[5010];
vector<int> f[5010];
int x[2510];
int y[2510];
bool vis[5010];

bool isEdge(int i){//判断边界 
	if(i%2)return false;
	i/=2;
	if(i<=a||i>a*(s-1))return true;
	if(i%a==1||i%a==0)return true;
	return false;
}

bool dfs(int start){
	vis[start]=1;
	if(isEdge(start))return true;
	for(int i=0;i<E[start].size();i++){
	
		if( !vis[E[start][i]] && (c[start][i]-f[start][i])>0 ){
			int key=0;
			for(int j=0;j<E[E[start][i]].size();j++){
				if(E[E[start][i]][j]==start){
					key=j;
					break;
				}
			}
			if(dfs(E[start][i])){
				f[start][i]++;
				f[E[start][i]][key]--;
				return true;
			}
		}
	}
	return false;
}

int main(){
	int p;
	scanf("%d",&p);
	while(p--){
		for(int i=0;i<5010;i++){
			E[i].clear();
			c[i].clear();
			f[i].clear();
		}
		scanf("%d%d%d",&s,&a,&b);
		for(int i=1;i<=b;i++){
			scanf("%d%d",&x[i],&y[i]);
		}
		
		//建图 
		for(int i=1;i<=a*s*2;i++){
			if(isEdge(i))continue;
			if(i%2){//入点 
				E[i].push_back(i+1);
				c[i].push_back(1);
				f[i].push_back(0);
				
				E[i+1].push_back(i);
				c[i+1].push_back(0);
				f[i+1].push_back(0);
			}else{//出点 
				E[i].push_back(i-a*2-1);
				E[i].push_back(i+a*2-1);
				E[i].push_back(i-3);
				E[i].push_back(i+1);
				c[i].push_back(1);c[i].push_back(1);c[i].push_back(1);c[i].push_back(1);
				f[i].push_back(0);f[i].push_back(0);f[i].push_back(0);f[i].push_back(0);
				
				E[i-a*2-1].push_back(i);
				E[i+a*2-1].push_back(i);
				E[i-3].push_back(i);
				E[i+1].push_back(i);
				c[i-a*2-1].push_back(0);c[i+a*2-1].push_back(0);
				c[i-3].push_back(0);c[i+1].push_back(0);
				f[i-a*2-1].push_back(0);f[i+a*2-1].push_back(0);
				f[i-3].push_back(0);f[i+1].push_back(0);
			}
		}
		
		int ans=0;
		for(int i=1;i<=b;i++){
			memset(vis,0,sizeof(vis));
			if(dfs( ((x[i]-1)*a+y[i])*2-1 )){
				ans++;
			}
		}
		if(b-ans){
			printf("not possible\n");
		}else{
			printf("possible\n");
		}
	}
	return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值