标签:
Description
Input
Output
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,负载为需求数量,跑最大流即可。
#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; }
标签:
原文地址:http://blog.csdn.net/maxichu/article/details/45132203