HDU 4322-Candy

感觉像最大流的题,就是想不出怎么建图~~

搜题解后发现建图思想太巧妙了:

1 -    源点0到1~N个糖果,容量为1,费用为0

2 -    根据like数组,like[i][j] == 1时在糖果j和人N+i之间建立有一条边,容量为1,费用为0

3*-    根据b[i]和K的值建立小孩和汇点之间的边:

                   如果b[i] 是  K 的倍数, 说明花费b[i] / K个喜欢的糖果可以达到b[i],建立一条边,费用为K,容量为b[i] / K;

                   否则,将这条边拆为两部分,第一部分是b[i] / K的部分,第二部分根据b[i] % K的部分。(如果b[i] % k == 0,说明b[i]是k的倍数;

                   若b[i] % k == 1, 特殊糖果和一般糖果价值一样,没必要当做特殊糖果处理)

建好图后,求最大费用最大流(只需将费用改为负的,然后套最小费用最大流即可).。得出特殊糖果匹配b[i]的最大值。看剩余的普通糖果是否满足缺少的b[i]。

表达能力不强,只能说到这程度了~~另外很诡异的是第一次程序进入死循环,提交后竟然a了。不理解啊不理解~~有兴趣的可以看下,求指教~~

代码:

#include<iostream>
#include<cstdio>
#include<cstring>
#include<climits>
#include<queue>
#include<algorithm>
using namespace std;
#define MAXN 1200

int B[22];
int like[22][22];
typedef struct
{
	int from, to, cap, flow, cost;
	int next;
}Node;
int src, tink, N, M, K, cnt, f;
int head[MAXN];
Node node[MAXN*2];
int dis[MAXN];
int pre[MAXN];
int re[MAXN];
int inq[MAXN];

void init()
{
	src = 0;
	tink = 1+M+N;
	cnt = 2;
	memset(node, 0, sizeof(node));
	memset(head, -1, sizeof(head));	
}

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

int MinCostMaxFlow(int s, int t)
{
	int i, u, v, ind, cap, cost, c = 0;
	f = 0; 
	queue<int> q;
	for(;;)
	{
		for(i = s; i <= t; i++)
		{
			dis[i] = INT_MAX;
		}
		dis[s] = 0;
		memset(inq, 0, sizeof(inq));
		q.push(s);
		inq[s] = 1;
		pre[s] = s;
		while(!q.empty())
		{
			u = q.front();
			q.pop();
			inq[u] = 0;
			//printf("%d\n", u);
			ind = head[u];
			for(; ind != -1; ind = node[ind].next)          //把这个地方的-1改为0,会进入死循环,但是提交也会ac,不理解
			{
				cap = node[ind].cap;
				cost = node[ind].cost;
				u = node[ind].from;
				v = node[ind].to;
			//	printf("%d\n", v);
				if(cap > 0 && dis[v] > dis[u] + cost)
				{
					dis[v] = dis[u] + cost;
					pre[v] = u;
					re[v] = ind;
					if(!inq[v])
					{
						inq[v] = 1;
						q.push(v);
					}
				}
			}
		}
		if(dis[t] == INT_MAX)
			break;
		for(u = t; u != s; u = pre[u])
		{
			node[re[u]].cap -= 1;
			node[re[u]^1].cap += 1;
		}
		f += 1;
		c += dis[t];
	}
	return c;
}

int main()
{
	int tcases, i, j, sumb, tt;
	scanf("%d", &tcases);
	tt = tcases;
	while(tcases--)
	{
		scanf("%d%d%d", &N, &M, &K);
		sumb = 0;
		init();
		for(i = 1; i <= M; i++)
		{
			scanf("%d", &B[i]);
			sumb += B[i];
			addEages(N+i, tink, B[i]/K, -K);
			if(B[i] % K > 1)
				addEages(N+i, tink, 1, -B[i]%K);
		}
		for(i = 1; i <= M; i++)
		{
			for(j = 1; j <= N; j++)
			{
				scanf("%d", &like[i][j]);
				if(like[i][j])
				{
					addEages(j, i+N, 1, 0);
				}	
			}
		}
		for(i = 1; i <= N; i++)
		{
			addEages(src, i, 1, 0);
		}
		/*for(i = 2; i < cnt; i++)
		{
			printf("%d\n", node[i].from);
			int tmp = head[node[i].from];
			while(tmp != -1)
			{
				printf("%d   ", node[tmp].to);
				tmp = node[tmp].next;
			}
			cout << endl;
		}*/
		printf("Case #%d: ", tt-tcases);
		int ans = MinCostMaxFlow(src, tink);
		if(sumb + ans <= N - f)
			printf("YES\n");
		else
			printf("NO\n");
	}
	return 0;
}




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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值