标签:
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
网友的不错,仿一下。。。,其实网络流大同小异
题目描述:
有n头奶牛,m个棚,每个奶牛对每个棚都有一个喜爱程度。当然啦,棚子也是有脾气的,并不是奶牛想住进来就住进来,超出棚子的最大容量了,棚子是拒绝的。现在要给每个奶牛安家,本宝宝是一个公正无私的人类,所以要找一个奶牛喜爱程度差值最小的方案(虽然这样大家的喜爱程度可能普遍偏低,因为绝对公平并不代表合理啊),问喜爱程度的区间最小为多大?
解题思路:
每个棚子并不是住一个奶牛,所以是多重匹配咯。匹配的时候二分枚举喜爱程度的区间大小,根据区间大小来枚举区间的起点和终点,然后跑多重匹配判断是否合法即可。注意咯,求得是区间大小。还有啊,还有啊,数据读入的时候maps[i][j]并不是i_th奶牛对j_th棚子的喜爱值,而是i_th奶牛对maps[i][j]棚子的喜爱程度为j。
#include <cstdio> #include <cstring> #include <iostream> #include <algorithm> using namespace std; const int maxn = 1010; int maps[maxn][22], vis[22], used[22][maxn]; int link[22], limit[22], n, m, s, e, mid; bool Find (int u) { for (int i=1; i<=m; i++) {//多重匹配 if (!vis[i] && maps[u][i]<e && s<=maps[u][i]) { vis[i] = 1; if (link[i] < limit[i]) {//i棚子未满 used[i][link[i] ++] = u; return true; } for (int j=0; j<limit[i]; j++)//i棚子已满,寻找增广路 if (Find(used[i][j])) { used[i][j] = u; return true; } } } return false; } bool hungry () { for (s=1; s<=m+1-mid; s++) {//枚举区间起点与终点 int ans = 0; e = s + mid; memset (link, 0, sizeof(link)); for (int i=1; i<=n; i++) { memset (vis, 0, sizeof(vis)); if (Find (i)) ans ++; } if (ans == n) return true; } return false; } int main () { while (scanf ("%d %d", &n, &m) != EOF) { for (int i=1; i<=n; i++) for (int j=1; j<=m; j++) { scanf ("%d", &mid); maps[i][mid] = j; } for (int i=1; i<=m; i++) scanf ("%d", &limit[i]); int left = 1, right = m, ans = 0; while (left<=right) {//二分枚举区间 mid = (right+left)/2; if (hungry()) { ans = mid; right = mid - 1 ; } else left = mid + 1 ; } printf ("%d\n", ans); } return 0; }
Steady Cow Assignment(二分图多重匹配+二分)(网络流)
标签:
原文地址:http://blog.csdn.net/u014665013/article/details/51346265