码迷,mamicode.com
首页 > 其他好文 > 详细

解题报告 之 POJ1149 PIGS

时间:2015-04-20 09:35:39      阅读:122      评论:0      收藏:0      [点我收藏+]

标签:

解题报告 之 POJ1149 PIGS


Description

Mirko works on a pig farm that consists of M locked pig-houses and Mirko can‘t unlock any pighouse because he doesn‘t have the keys. Customers come to the farm one after another. Each of them has keys to some pig-houses and wants to buy a certain number of pigs. 
All data concerning customers planning to visit the farm on that particular day are available to Mirko early in the morning so that he can make a sales-plan in order to maximize the number of pigs sold. 
More precisely, the procedure is as following: the customer arrives, opens all pig-houses to which he has the key, Mirko sells a certain number of pigs from all the unlocked pig-houses to him, and, if Mirko wants, he can redistribute the remaining pigs across the unlocked pig-houses. 
An unlimited number of pigs can be placed in every pig-house. 
Write a program that will find the maximum number of pigs that he can sell on that day.

Input

The first line of input contains two integers M and N, 1 <= M <= 1000, 1 <= N <= 100, number of pighouses and number of customers. Pig houses are numbered from 1 to M and customers are numbered from 1 to N. 
The next line contains M integeres, for each pig-house initial number of pigs. The number of pigs in each pig-house is greater or equal to 0 and less or equal to 1000. 
The next N lines contains records about the customers in the following form ( record about the i-th customer is written in the (i+2)-th line): 
A K1 K2 ... KA B It means that this customer has key to the pig-houses marked with the numbers K1, K2, ..., KA (sorted nondecreasingly ) and that he wants to buy B pigs. Numbers A and B can be equal to 0.

Output

The first and only line of the output should contain the number of sold pigs.

Sample Input

3 3
3 1 10
2 1 2 2
2 1 3 3
1 2 6

Sample Output

7


题目大意:有m个猪圈,n个顾客。钥匙都掌握在顾客手中(这一点很值得吐槽,这个猪场老板脑子进水了。。。)。顾客按照顺序到来,他会把他掌管钥匙对应的猪圈全打开,猪场老板可以调整分配方式(每个猪圈都可以容纳无限头)。当前顾客对猪有一定需求量,猪场老板自由决定要从所有打开的猪圈中卖给该顾客多少猪(1<=pig_sell<=need)。交易完成后所有猪圈重新锁上。问最终老板一共可以卖多少猪?(感觉最大流的题首先都是阅读理解。。。。妈妈再也不用担心我做Johnson出的题了)


分析:明显是最大流,不过这道题重点难点在于建图,是一种很巧妙的思路。引入第一个打开某猪圈的人这个概念。将src连一条边到第一个打开某猪圈的人,流量为猪圈猪数量,一种更好的优化是将顾客 i 第一个打开的所有猪圈的猪总数从src连一条边到 i 。重点来了,如果不是第一个打开的人呢?此时只需要看看谁是第一个打开这个猪圈的人,连一条边到第一个人身上即可,负载为INF。因为第一打开猪圈的人可以随意调配把猪放到哪个猪圈,所以这个人能接触到的所有猪下一个打开的人都可以通用(大不了全部调剂到同一个猪圈)。(BTW,有一种更优的方法是连边后更新一下最近打开某猪圈的人,之后的人直接与之相连INF即可,目测是DFS和BFS更省时间了)。最后将所有顾客连一条边到des,负载为需求数量,跑最大流即可。


另外出现了一个很奇葩的问题:本来我数组开小了,但是却不是RTE而是TLE,我一直以为是算法不够快,但是感觉数据量很小。后来终于发现是数组开小了,我猜是数组数据被刷了导致有死循环。

上代码:
#include<cstdio>
#include<cstring>
#include<queue>
#include<algorithm>
using namespace std;

const int MAXN = 3100;
const int MAXM = 20010;
const int INF = 0x3f3f3f3f;


struct Edge
{
	int  to, cap, next;
};


Edge edge[MAXM];
int level[MAXN];
int head[MAXN];
int first[MAXN];
int pigs[MAXN];
int src, des, cnt;


inline void addedge(int from, int to, int cap)
{
	edge[cnt].to = to;
	edge[cnt].cap = cap;
	edge[cnt].next = head[from];
	head[from] = cnt++;

	edge[cnt].to = from;
	edge[cnt].cap = 0;
	edge[cnt].next = head[to];
	head[to] = cnt++;
}


int bfs()
{
	queue<int> q;
	while (!q.empty())
		q.pop();
	memset(level, -1, sizeof level);
	level[src] = 0;
	q.push(src);

	while (!q.empty())
	{
		int u = q.front();
		q.pop();

		for (int i = head[u]; i != -1; i = edge[i].next)
		{
			int v = edge[i].to;
			if (edge[i].cap > 0 && level[v] == -1)
			{
				level[v] = level[u] + 1;
				q.push(v);
			}
		}
	}
	return level[des] != -1;
}


int dfs(int u, int f)
{
	if (u == des) return f;
	int tem;
	for (int i = head[u]; i != -1; i = edge[i].next)
	{
		int v = edge[i].to;
		if (edge[i].cap > 0 && level[v] == level[u] + 1)
		{
			tem = dfs(v, min(f, edge[i].cap));
			if (tem > 0)
			{
				edge[i].cap -= tem;
				edge[i ^ 1].cap += tem;
				return tem;
			}
		}
	}
	level[u] = -1;
	return 0;
}


int Dinic()
{
	int ans = 0, tem;

	while (bfs())
	{
		while (tem = dfs(src, INF))
		{
			ans += tem;
		}
	}
	return ans;
}


int main()
{
	int n, m;
	src = 0;
	des = 305;
	while (~::scanf("%d%d", &m, &n))
	{

		memset(head, -1, sizeof head);
		memset(first, -1, sizeof first);
		cnt = 0;
		int keys, keynum, buy;

		for (int i = 1; i <= m; i++)
		{
			scanf("%d", &pigs[i]);
		}

		for (int i = 1; i <= n; i++)
		{
			scanf("%d", &keys);
			int mine = 0;
			for (int j = 1; j <= keys; j++)
			{
				scanf("%d", &keynum);
				if (first[keynum] == -1)
				{
					first[keynum] = i;
					mine += pigs[keynum];
				}
				else
				{
					addedge(first[keynum], i, INF);
				}
			}
			if (mine)
				addedge(src, i, mine);

			scanf("%d", &buy);
			addedge(i, des, buy);
		}

		printf("%d\n", Dinic());
	}

	return 0;
}

大大微软杯加油哈!

解题报告 之 POJ1149 PIGS

标签:

原文地址:http://blog.csdn.net/maxichu/article/details/45132203

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!