HDU 4292-Food

和poj3281比较像,都是一份食物加一份水匹配一个人的问题,可是这次成都的网选题数据严的多,再用邻接矩阵加EK算法就会各种超时~~

把图用邻接表建,然后用SAP找增广路即可a掉这道题。

悲剧的我在这题wa了无数次,只因为建图的时候邻接表编号从0开始,和head初始化的值重复了。

以后建邻接表一定要初始化-1,编号从2开始,又不缺那点空间~~

有图有真相,牢记错误,以免再犯:


代码如下:

#include<iostream>
#include<cstdio>
#include<cstring>
#include<climits>
#include<algorithm>
//#define min(a,b) (a<b?a:b)
#define MAXN 810
using namespace std;

int N, ff, dd, cnt, source, tink;
typedef struct
{
	int from, to, cap, op;
	int next;
}Node;
Node node[MAXN*MAXN];
int pre[MAXN];
int head[MAXN];
int dis[MAXN];
int num[MAXN];

int food[210];
int drink[210];
char s[210];

void init()
{
	cnt = 0;
	memset(node, 0, sizeof(node));
	memset(head, -1, sizeof(head));
	source = 0;
	tink = 2*N+ff+dd+1;
}

int dfs(int x, int flow)
{
	if(x == tink) 
		return flow;
	int f = 0, mind = tink;
	for(int t = head[x]; t != -1; t = node[t].next)
	{
		if(node[t].cap)
		{
			if(dis[x] == dis[node[t].to] + 1)
			{
				int temp = dfs(node[t].to, min(flow-f, node[t].cap));
				node[t].cap -= temp;
				node[node[t].op].cap += temp;
				f += temp;
				
				if(dis[source] >= tink+1)
					return f;
				if(flow == f)
					break;
			}
			mind = min(mind, dis[ node[t].to ]);
		}
	}
	if(!f)
	{
		if(!(--num[dis[x]]))
			dis[source] = tink+1;
		++num[dis[x] = mind + 1];
	}
	return f;
}

int SAP()
{
	int ans = 0;
	memset(dis, 0, sizeof(dis));
	memset(num, 0, sizeof(num));
	num[0] = 2*N + ff + dd + 2;
	while(dis[source] < 2*N+ff+dd+2)
		ans += dfs(source, INT_MAX);
	return ans;
}

void Add(int u, int v, int cap)
{
	node[cnt].from = u;
	node[cnt].to = v;
	node[cnt].cap = cap;
	node[cnt].op = cnt + 1;
	node[cnt].next = head[u];
	head[u] = cnt++;
	
	node[cnt].from = v;
	node[cnt].to = u;
	node[cnt].cap = 0;
	node[cnt].op = cnt - 1;
	node[cnt].next = head[v];
	head[v] = cnt++;	
}

int main()
{
	int i, j;
	while(scanf("%d%d%d", &N, &ff, &dd) != EOF)
	{
		init();
		for(i = 1; i <= ff; i++)
		{
			scanf("%d", &food[i]);
		}
		for(i = 1; i <= dd; i++)
		{
			scanf("%d", &drink[i]);
		}
		for(i = 1; i <= N; i++)
		{
			scanf("%s", s);
			for(j = 1; j <= ff; j++)
			{
				if(s[j-1] == 'Y')
				{
					Add(2*N+j, i, 1);
				}
			}
		}
		for(i = 1; i <= N; i++)
		{
			scanf("%s", s);
			for(j = 1; j <= dd; j++)
			{
				if(s[j-1] == 'Y')
				{
					Add(i+N, 2*N+j+ff, 1);
				}
			}
		}
		for(i = 1; i <= N; i++)
		{
			Add(i, i+N, 1);
		}
		for(i = 1; i <= ff; i++)
		{
			Add(0, 2*N+i, food[i]);
		}
		for(i = 1; i <= dd; i++)
		{
			Add(2*N+ff+i, 2*N+ff+dd+1, drink[i]);
		}
		/*for(i = 1; i < cnt; i++)
		{
			cout << node[i].from << " "<<node[i].to << endl;
		}*/
		printf("%d\n", SAP());
	}
	return 0;
}



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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值