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;
}

 

posted @ 2021-04-05 15:47  cono奇犽哒  阅读(51)  评论(0)    收藏  举报