答题报告 之 POJ1149 PIGS
解题报告 之 POJ1149 PIGS
大大微软杯加油哈!
解题报告 之 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.
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.
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; }