Time Limit: 1000MS | Memory Limit: 65536K | |
Total Submissions: 6029 | Accepted: 2083 |
Description
Input
Output
Sample Input
6 4 1 2 3 4 2 3 1 4 4 2 3 1 3 1 2 4 1 3 4 2 1 4 2 3 2 1 3 2
Sample Output
2
Hint
Each cow can be assigned to her first or second choice: barn 1 gets cows 1 and 5, barn 2 gets cow 2, barn 3 gets cow 4, and barn 4 gets cows 3 and 6.
犯二,忘建源点到每头牛的边了。没想到过了测试数据,悲催,WA了一次。
题意:给你N头牛、B个畜栏以及畜栏的容量,又根据喜欢程度给出每头牛心中这B个畜栏的排名。
为了便于理解,举个例子。假如一头牛心中对3个畜栏的排名为——1畜栏、3畜栏、2畜栏。若该牛被分配到畜栏3,它的辛福值为2,若被分配到畜栏1,它的幸福值为3,若被分配到畜栏2,它的辛福值为1。
现在让你找出一种方案使得每头牛都属于一个畜栏,并且所有牛的最大幸福值与最小幸福值的差最小,让你输出这个最小差值 + 1。 题目保证至少会有一种方案使得每头牛属于一个畜栏。
思路:枚举差值,根据该差值所得到的 幸福值的上下界建边。跑最大流,看是否满流。
建图:对当前枚举上下界[L, R],设置超级源点source,超级汇点sink。
1,source到每头牛建边,容量为1,表示一头牛只能选择一个畜栏;
2,若牛选择畜栏的幸福值在[L, R]区间里面,则该牛向畜栏建边,容量为1;
3,所有畜栏向sink建边,容量为当前畜栏可容纳的牛的数目。
跑最大流,看是否满流即可。
AC代码:
#include <cstdio> #include <cstring> #include <queue> #include <algorithm> #define MAXN 1500 #define MAXM 50000+10 #define INF 0x3f3f3f3f using namespace std; struct Edge { int from, to, cap, flow, next; }; Edge edge[MAXM], Redge[MAXM]; int head[MAXN], edgenum, Rhead[MAXN], Redgenum; int dist[MAXN], cur[MAXN]; bool vis[MAXN]; int Map[MAXN][25]; int N, B; int sink, source; void init() { edgenum = 0; memset(head, -1, sizeof(head)); } void addEdge(int u, int v, int w) { Edge E1 = {u, v, w, 0, head[u]}; edge[edgenum] = E1; head[u] = edgenum++; Edge E2 = {v, u, 0, 0, head[v]}; edge[edgenum] = E2; head[v] = edgenum++; } void input() { int a; init();source = 0, sink = N+B+1; for(int i = 1; i <= N; i++) { addEdge(source, i, 1);//source 向 每头牛建边 for(int j = 1; j <= B; j++) { scanf("%d", &a); Map[i][a] = B - j + 1;//记录辛福值 按排名前后递减 } } for(int i = 1; i <= B; i++) { scanf("%d", &a); addEdge(i+N, sink, a);//每个畜栏向sink建边 } } void getMap(int L, int R) { for(int i = 1; i <= N; i++) { for(int j = 1; j <= B; j++) { if(Map[i][j] >= L && Map[i][j] <= R)//根据上下界 建边 addEdge(i, j+N, 1); } } } bool BFS(int s, int t) { queue<int> Q; memset(dist, -1, sizeof(dist)); memset(vis, false, sizeof(vis)); dist[s] = 0; vis[s] = true; Q.push(s); while(!Q.empty()) { int u = Q.front(); Q.pop(); for(int i = head[u]; i != -1; i = edge[i].next) { Edge E = edge[i]; if(!vis[E.to] && E.cap > E.flow) { dist[E.to] = dist[u] + 1; if(E.to == t) return true; vis[E.to] = true; Q.push(E.to); } } } return false; } int DFS(int x, int a, int t) { if(x == t || a == 0) return a; int flow = 0, f; for(int &i = cur[x]; i != -1; i = edge[i].next) { Edge &E = edge[i]; if(dist[E.to] == dist[x] + 1 && (f = DFS(E.to, min(a, E.cap - E.flow), t)) > 0) { edge[i].flow += f; edge[i^1].flow -= f; flow += f; a -= f; if(a == 0) break; } } return flow; } int Maxflow(int s, int t) { int flow = 0; while(BFS(s, t)) { memcpy(cur, head, sizeof(head)); flow += DFS(s, INF, t); } return flow; } void solve() { memcpy(Redge, edge, sizeof(edge)); memcpy(Rhead, head, sizeof(head)); Redgenum = edgenum; bool flag = false; int ans; for(int i = 0; i < B; i++)//枚举差值 { for(int j = 1; j <= B-i; j++)//枚举下界 最低辛福值 { memcpy(edge, Redge, sizeof(Redge));//copy memcpy(head, Rhead, sizeof(Rhead)); edgenum = Redgenum; getMap(j, j + i); if(Maxflow(source, sink) == N)//最先找到的 一定最优 { flag = true; ans = i; break; } } if(flag) break; } printf("%d\n", ans+1); } int main() { while(scanf("%d%d", &N, &B) != EOF) { input(); solve(); } return 0; }
版权声明:本文为博主原创文章,未经博主允许不得转载。
poj 3189 Steady Cow Assignment 【最大流】【枚举上下界 判断是否满流】
原文:http://blog.csdn.net/chenzhenyu123456/article/details/48055983