UVa 563 Crimewave / 最大流EK

这题有很多第一次

第一次用了数组表示的邻接表 以前都是用vector

第一次学了拆点 参考大神的 最大流建图是重点

题意看图 就是所有点要到边界 不能转弯超过一次 不能重叠

第一次不懂什么是拆点 看了下这个就懂了 说的蛮好的

http://www.cnblogs.com/scau20110726/archive/2012/12/20/2827177.html

#include <cstdio>
#include <cstring>
#include <queue>
#include <algorithm>
using namespace std;
const int MAX = 30010;
const int MAXN = 5010;
struct edge
{
	int u;
	int v;
	int next;
	int flow;
	int cap;
}e[MAX];
int dir[4][2] = {1,0,-1,0,0,1,0,-1};
int first[MAXN];
int p[MAXN];
int a[MAXN];
int edgenum;
int n,m,num;
int s,t,f;

void add(int u,int v)
{
	e[edgenum].u = u;
	e[edgenum].v = v;
	e[edgenum].flow = 0;
	e[edgenum].cap = 1;
	e[edgenum].next = first[u];
	first[u] = edgenum++;
	e[edgenum].u = v;
	e[edgenum].v = u;
	e[edgenum].flow = 0;
	e[edgenum].cap = 0;
	e[edgenum].next = first[v];
	first[v] = edgenum++;
}

void EK()
{
	queue <int> q;
	f = 0;
	while(1)
	{
		memset(a,0,sizeof(a));
		memset(p,-1,sizeof(p));
		a[0] = 999999999;
		q.push(0);
		while(!q.empty())
		{
			int u = q.front();
			q.pop();
			for(int k = first[u]; k != -1; k = e[k].next)
			{
				int v = e[k].v;
				if(!a[v] && e[k].cap > e[k].flow)
				{
					p[v] = k;
					q.push(v);
					a[v] = min(a[u],e[k].cap - e[k].flow);
				}
			}
		}
		if(a[t] == 0)
			break;
		for(int k = p[t]; k != -1; k = p[e[k].u])
		{
			e[k].flow += a[t];
			e[k^1].flow -= a[t];
		}
		f += a[t];
	}
}

void init()
{	
	int i,j,k;
	memset(first,-1,sizeof(first));
	edgenum = 0;
	for(i = 1; i <= n; i++)
	{
		for(j = 1; j <= m; j++)
		{
			int u = (i - 1) * m + j;
			int e = u + n * m;
			add(u,e);
			for(k = 0; k < 4; k++)
			{
				int x = i + dir[k][0];
				int y = j + dir[k][1];
				if(x >= 1 && x <= n && y >= 1 && y <= m)
				{
					int uu = (x - 1) * m + y;
					add(e,uu);
				}
				else
					add(e,t);
			}
		}
	}
	for(i = 1; i <= num; i++)
	{
		scanf("%d %d",&j,&k);
		add(s,(j - 1) * m + k);
	}
}
int main()
{
	int cas,i;
	scanf("%d",&cas);
	while(cas--)
	{
		scanf("%d %d %d",&n,&m,&num);
		s = 0;
		t = n * m * 2 + 1;
		init();
		EK();
		if(f == num)
			puts("possible");
		else
			puts("not possible");
	}
	return 0;
}


 

 

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值