标签:
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