P2857 [USACO06FEB]Steady Cow Assignment G(网络瘤+二分)
思路:如果不是求所有牛中评分最高与最低的差值最小,而是求牛最多的匹配成功数,
大家应该都会做,也就是把牛棚也看作节点,然后牛与喜欢的牛棚连边,做一个二分图,
最大流匹配一下,而这题不是叫咱们求最多匹配成功数,而是所有牛都匹配成功的情况下,
让所有牛中对所在牛棚评分最高与最低的差值最小,怎么做呢?感觉也没啥特别的方法啊~
犹豫不决,二分解决。
我们二分当前的差值,然后遍历当前插值下的可能选择的区间,假设b=5,当前二分差值x=2,
我们就对(1,2),(2,3),(3,4),(4,5)这些区间分别建图,也就是
牛只能选择喜欢程度为(1,2)的牛棚,即只与这些牛棚连边,然后跑最大流,如果上述区间中
有任何一个满足最大流为n,则说明x=2是可取的,再继续向下二分,直到结束。
还有个问题,谁知道为啥我写博客的时候字符只能是中文输入法,就像这样,,,,,,
这样eeemmmm...,;;;;,明明换成英文的为啥也还是中文的字符,之前都好好的啊,我太难了....
AC代码:
int sa[1005][25], v[maxn]; bool check(int x) { for (int l = 1,r=x; r <= b; l++,r++) {//在差值为x的所有情况 memset(hd, 0, sizeof(hd)); tot = 1; for (int j = 1; j <= n; j++)add(s, j, 1);//牛与源点连边 for (int j = 1; j <= b; j++)add(j+n, d, v[j]);//牛棚与汇点连边,有容量限制 for (int j = 1; j <= n; j++) { for (int k = l; k <= r; k++) {//对该区间下的牛棚连边 add(j, n+sa[j][k], 1); } } if (n == dinic())return true;//网络瘤 } return false; } int main() { //freopen("test.txt", "r", stdin); scanf("%d%d", &n, &b); s = n + b + 1, d = n + b + 2; for (int i = 1; i <= n; i++) { for (int j = 1; j <= b; j++) { scanf("%d", &sa[i][j]); } } for (int i = 1; i <= b; i++) { scanf("%d", &v[i]); } int l = 1, r = b,mid; int ans = 0; do{//二分差值 mid = (l + r) >> 1; if (check(mid)) {//当前差值可行 ans = mid; r = mid - 1; } else { l = mid + 1; } } while (l <= r); printf("%d\n", ans); return 0; }