POJ3189 Steady Cow Assignment —— 二分图多重匹配/最大流 + 二分

题目链接:https://vjudge.net/problem/POJ-3189

Steady Cow Assignment

Time Limit: 1000MS   Memory Limit: 65536K
Total Submissions: 6979   Accepted: 2418

Description

Farmer John‘s N (1 <= N <= 1000) cows each reside in one of B (1 <= B <= 20) barns which, of course, have limited capacity. Some cows really like their current barn, and some are not so happy.

FJ would like to rearrange the cows such that the cows are as equally happy as possible, even if that means all the cows hate their assigned barn.

Each cow gives FJ the order in which she prefers the barns. A cow‘s happiness with a particular assignment is her ranking of her barn. Your job is to find an assignment of cows to barns such that no barn‘s capacity is exceeded and the size of the range (i.e., one more than the positive difference between the the highest-ranked barn chosen and that lowest-ranked barn chosen) of barn rankings the cows give their assigned barns is as small as possible.

Input

Line 1: Two space-separated integers, N and B

Lines 2..N+1: Each line contains B space-separated integers which are exactly 1..B sorted into some order. The first integer on line i+1 is the number of the cow i‘s top-choice barn, the second integer on that line is the number of the i‘th cow‘s second-choice barn, and so on.

Line N+2: B space-separated integers, respectively the capacity of the first barn, then the capacity of the second, and so on. The sum of these numbers is guaranteed to be at least N.

Output

Line 1: One integer, the size of the minumum range of barn rankings the cows give their assigned barns, including the endpoints.

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

Explanation of the sample:

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.

Source

USACO 2006 February Gold

题解:

题意:有n头牛, 安排到m个牲棚里住。每头牛对每个牲棚都有一个好感度排名。主人为了使得这些牛尽可能满意,规定了获得最低好感度的牛和获得最高好感度的牛的好感度差值最小(即好感度跨度最小)。

1.二分跨度。然后对于每个跨度,枚举最低好感度(最高好感度也就可以求出),然后开始建图:如果某头牛对某个牲棚的好感度在这个范围内,则连上边;否则不连。

2.用二分图多重匹配或者最大流,求出是否每头牛都可以被安排到某个牲棚中。如果可以,则缩小跨度,否则增大跨度。

多重匹配:

 1 #include <iostream>
 2 #include <cstdio>
 3 #include <cstring>
 4 #include <cstdlib>
 5 #include <string>
 6 #include <vector>
 7 #include <map>
 8 #include <set>
 9 #include <queue>
10 #include <sstream>
11 #include <algorithm>
12 using namespace std;
13 const int INF = 2e9;
14 const int MOD = 1e9+7;
15 const int MAXM = 20+10;
16 const int MAXN = 1e3+10;
17
18 int uN, vN, Rank[MAXN][MAXM];
19 int num[MAXM], linker[MAXM][MAXN];
20 bool g[MAXN][MAXM], used[MAXM];
21
22 bool dfs(int u)
23 {
24     for(int v = 1; v<=vN; v++)
25     if(g[u][v] && !used[v])
26     {
27         used[v] = true;
28         if(linker[v][0]<num[v])
29         {
30             linker[v][++linker[v][0]] = u;
31             return true;
32         }
33         for(int i = 1; i<=num[v]; i++)
34         if(dfs(linker[v][i]))
35         {
36             linker[v][i] = u;
37             return true;
38         }
39     }
40     return false;
41 }
42
43 bool hungary()
44 {
45     for(int i = 1; i<=vN; i++)
46         linker[i][0] = 0;
47     for(int u = 1; u<=uN; u++)
48     {
49         memset(used, false, sizeof(used));
50         if(!dfs(u)) return false;
51     }
52     return true;
53 }
54
55 bool test(int mid)
56 {
57     for(int down = 1; down<=vN-mid+1; down++)
58     {
59         int up = down+mid-1;
60         memset(g, false, sizeof(g));
61         for(int i = 1; i<=uN; i++)
62         for(int j = down; j<=up; j++)
63                 g[i][Rank[i][j]] = true;
64
65         if(hungary()) return true;
66     }
67     return false;
68 }
69
70 int main()
71 {
72     while(scanf("%d%d", &uN, &vN)!=EOF)
73     {
74         for(int i = 1; i<=uN; i++)
75         for(int j = 1; j<=vN; j++)
76             scanf("%d", &Rank[i][j]);
77
78         for(int i = 1; i<=vN; i++)
79             scanf("%d", &num[i]);
80
81         int l = 1, r = vN;
82         while(l<=r)
83         {
84             int mid = (l+r)>>1;
85             if(test(mid))
86                 r = mid - 1;
87             else
88                 l = mid + 1;
89         }
90         printf("%d\n", l);
91     }
92 }

最大流:

  1 #include <iostream>
  2 #include <cstdio>
  3 #include <cstring>
  4 #include <cstdlib>
  5 #include <string>
  6 #include <vector>
  7 #include <map>
  8 #include <set>
  9 #include <queue>
 10 #include <sstream>
 11 #include <algorithm>
 12 using namespace std;
 13 const int INF = 2e9;
 14 const int MOD = 1e9+7;
 15 const int MAXM = 20+10;
 16 const int MAXN = 2e3+10;
 17
 18 struct Edge
 19 {
 20     int to, next, cap, flow;
 21 }edge[MAXN*MAXN];
 22 int tot, head[MAXN];
 23
 24 int uN, vN, Rank[MAXN][MAXM], num[MAXM];
 25 int gap[MAXN], dep[MAXN], pre[MAXN], cur[MAXN];
 26
 27 void add(int u, int v, int w)
 28 {
 29     edge[tot].to = v; edge[tot].cap = w; edge[tot].flow = 0;
 30     edge[tot].next = head[u]; head[u] = tot++;
 31     edge[tot].to = u; edge[tot].cap = 0; edge[tot].flow = 0;
 32     edge[tot].next = head[v]; head[v] = tot++;
 33 }
 34
 35 int sap(int start, int end, int nodenum)
 36 {
 37     memset(gap,0,sizeof(gap));
 38     memset(dep,0,sizeof(dep));
 39     memcpy(cur,head,sizeof(head));
 40
 41     int u = start;
 42     pre[u] = -1;
 43     gap[0] = nodenum;
 44     int maxflow = 0;
 45     while(dep[start]<nodenum)
 46     {
 47         bool flag = false;
 48         for(int i = cur[u]; i!=-1; i=edge[i].next)
 49         {
 50             int v = edge[i].to;
 51             if(edge[i].cap-edge[i].flow && dep[v]+1==dep[u])
 52             {
 53                 flag = true;
 54                 cur[u] = pre[v] = i;
 55                 u = v;
 56                 break;
 57             }
 58         }
 59
 60         if(flag)
 61         {
 62             if(u==end)
 63             {
 64                 int minn = INF;
 65                 for(int i = pre[u]; i!=-1; i=pre[edge[i^1].to])
 66                     if(minn>edge[i].cap-edge[i].flow)
 67                         minn = edge[i].cap-edge[i].flow;
 68                 for(int i = pre[u]; i!=-1; i=pre[edge[i^1].to])
 69                 {
 70                     edge[i].flow += minn;
 71                     edge[i^1].flow -= minn;
 72                 }
 73                 u = start;
 74                 maxflow += minn;
 75             }
 76         }
 77
 78         else
 79         {
 80             int minn = nodenum;
 81             for(int i = head[u]; i!=-1; i=edge[i].next)
 82                 if(edge[i].cap-edge[i].flow && dep[edge[i].to]<minn)
 83                 {
 84                     minn = dep[edge[i].to];
 85                     cur[u] = i;
 86                 }
 87             gap[dep[u]]--;
 88             if(gap[dep[u]]==0) break;
 89             dep[u] = minn+1;
 90             gap[dep[u]]++;
 91             if(u!=start) u = edge[pre[u]^1].to;
 92         }
 93     }
 94     return maxflow;
 95 }
 96
 97 bool test(int mid)
 98 {
 99     for(int down = 1; down<=vN-mid+1; down++)
100     {
101         tot = 0;
102         memset(head, -1, sizeof(head));
103         for(int i = 1; i<=uN; i++)
104         {
105             add(0, i, 1);
106             int up = down+mid-1;
107             for(int j = down; j<=up; j++)
108                 add(i, uN+Rank[i][j], 1);
109         }
110         for(int i = 1; i<=vN; i++)
111             add(uN+i, uN+vN+1, num[i]);
112
113         int maxflow = sap(0, uN+vN+1, uN+vN+2);
114         if(maxflow==uN) return true;
115     }
116     return false;
117 }
118
119 int main()
120 {
121     while(scanf("%d%d", &uN, &vN)!=EOF)
122     {
123         for(int i = 1; i<=uN; i++)
124         for(int j = 1; j<=vN; j++)
125             scanf("%d", &Rank[i][j]);
126
127         for(int i = 1; i<=vN; i++)
128             scanf("%d", &num[i]);
129
130         int l = 1, r = vN;
131         while(l<=r)
132         {
133             int mid = (l+r)>>1;
134             if(test(mid))
135                 r = mid - 1;
136             else
137                 l = mid + 1;
138         }
139         printf("%d\n", l);
140     }
141 }

时间: 2024-10-07 16:08:37

POJ3189 Steady Cow Assignment —— 二分图多重匹配/最大流 + 二分的相关文章

POJ3189_Steady Cow Assignment(二分图多重匹配/网络流)

解题报告 http://blog.csdn.net/juncoder/article/details/38340447 题目传送门 题意: B个猪圈,N头猪,每头猪对每个猪圈有一个满意值,要求安排这些猪使得最大满意和最小满意的猪差值最小 思路: 二分图的多重匹配问题; 猪圈和源点连边,容量为猪圈容量,猪与汇点连边,容量1; 猪圈和猪之间连线取决所取的满意值范围; 二分查找满意值最小差值的范围. #include <iostream> #include <cstring> #incl

POJ2289 Jamie&#39;s Contact Groups —— 二分图多重匹配/最大流 + 二分

题目链接:https://vjudge.net/problem/POJ-2289 Jamie's Contact Groups Time Limit: 7000MS   Memory Limit: 65536K Total Submissions: 8147   Accepted: 2736 Description Jamie is a very popular girl and has quite a lot of friends, so she always keeps a very lon

POJ3189_Steady Cow Assignment(二分图多重匹配/网络流+二分构图)

解题报告 http://blog.csdn.net/juncoder/article/details/38340447 题目传送门 题意: B个猪圈,N头猪.每头猪对每一个猪圈有一个惬意值.要求安排这些猪使得最大惬意和最小惬意的猪差值最小 思路: 二分图的多重匹配问题; 猪圈和源点连边,容量为猪圈容量.猪与汇点连边,容量1; 猪圈和猪之间连线取决所取的惬意值范围; 二分查找惬意值最小差值的范围. #include <iostream> #include <cstring> #inc

POJ 3189--Steady Cow Assignment【二分图多重匹配 &amp;&amp; 最大流求解 &amp;&amp; 枚举 &amp;&amp; 经典】

Steady Cow Assignment Time Limit: 1000MS   Memory Limit: 65536K Total Submissions: 6023   Accepted: 2078 Description Farmer John's N (1 <= N <= 1000) cows each reside in one of B (1 <= B <= 20) barns which, of course, have limited capacity. So

Steady Cow Assignment---poj3189(多重匹配+二分)

题目链接:http://poj.org/problem?id=3189 题意:有n头牛,B个牛棚,每头牛对牛棚都有一个喜欢度,接下来输入N*B的矩阵第i行第j列的数x表示:第i头牛第j喜欢的是x; 第i个牛棚最多存Max[i]头牛,最后求牛棚的排名区间,意思就是假如一个牛棚中有最喜欢这个牛棚的牛(那么就是第一喜欢1)和也有最不喜欢这个牛棚的牛(那么就是第B喜欢B),答案就是1--B的区间大小B-1+1,问怎么安排能让这个区间值最小,求最小值: 由于B的取值范围较小,所以可以枚举所有的区间,求符合

poj3189 Steady Cow Assignment --- 多重匹配,二分图匹配解法

有n头牛,m个牛棚,每头牛对牛棚的满意程度有一个排序,每个牛棚有牛数限制. 问如何分配各个牛,使得所有牛的满意程度的差值最小. 这题首先可以想到二分答案,对于每一种差值来求是否可行. 不想再搞网络流,学习了下二分图匈牙利解法.. 匹配时,对于每一种选择(牛棚),若满足范围,且有多余的容量,则匹配: 否则,对于该牛棚已经匹配过的牛进行增广. #include <iostream> #include <cstdlib> #include <cstring> #include

POJ3189 Steady Cow Assignment(二分图多重匹配)

题意: N头牛M个棚,每头牛对每个棚都有喜爱顺序 每个棚都有自己的容量 问你怎么分配使得所有牛的喜爱程度差距最小 思路: l r表示一段喜爱程度的范围 建图就按l 到 r里的棚子建 然后两个标移动从头到尾就可以扫出最小值了 /* *********************************************** Author :devil Created Time :2016/5/17 22:28:45 ****************************************

POJ3189 Steady Cow Assignment(最大流)

题目大概说,有n头牛和b块草地,每头牛心中分别对每块草地都有排名,草地在牛中排名越高牛安排在那的幸福度就越小(...),每块草地都能容纳一定数量的牛.现在要给这n头牛分配草地,牛中的幸福度最大与幸福度最小的差值越小越好,问最小能多小. 显然又是枚举结果跑最大流看是否合法.不过,枚举幸福度的差值是做不了的,应该要枚举的是幸福度的最大值和幸福度的最小值.然后建图没啥好说的..最后的结果要加1,因为题目说“including the endpoints”,虽然不知道什么意思.. 1 #include<

Poj 2289 Jamie&#39;s Contact Groups (二分+二分图多重匹配)

题目链接: Poj 2289 Jamie's Contact Groups 题目描述: 给出n个人的名单和每个人可以被分到的组,问将n个人分到m个组内,并且人数最多的组人数要尽量少,问人数最多的组有多少人? 解题思路: 二分图多重匹配相对于二分匹配来说不再是节点间的一一对应,而是Xi可以对应多个Yi.所以我们就需要一个限制(Xi最多匹配几个Yi).当Yi需要匹配Xi的时候,Xi的匹配未到上限,直接匹配,否则进行增广路.其实是二分图多重匹配的模板题,再套一个二分枚举最多组的人数就OK咯.下面就上板