zoukankan      html  css  js  c++  java
  • 【最小割】[SHOI2007]善意的投票

    [SHOI2007]善意的投票

    思路

    把小朋友视为点,“不睡午觉”和“睡午觉”这两种结果作为源点和汇点。

    要求冲突数最小,即找出一种割边方式使点划分为两个集合,且割掉的边数最小。

    将想“不睡午觉”的小朋友与源点连一条边(s→i),如果割掉了这条边表示这个小朋友与自身意愿冲突;同理,将想“睡午觉”的小朋友与汇点连一条边(i→t)

    最后,好朋友之间连双向边,割掉边代表违背了好朋友的意愿。

    以上所有边权均为(1)

    然后跑最大流即可。注意因为加上了源点和汇点,实际图上的点有(n+2)这么多

    void addn(int&cnt_e, int head[], Edge e[], int u, int v, LL w) {
        //网络流建图
        e[++cnt_e].next = head[u]; e[cnt_e].from = u; e[cnt_e].to = v; e[cnt_e].w = w; head[u] = cnt_e;
        e[++cnt_e].next = head[v]; e[cnt_e].from = v; e[cnt_e].to = u; e[cnt_e].w = 0; head[v] = cnt_e;
    }
    
    int cnt_e = 0, head[maxn], n, m;
    int s, t;
    int cur[maxn], depth[maxn], gap[maxn];
    int wish[maxn];
    LL Maxflow = 0;
    
    void bfs() {
        mem(depth, -1);
        mem(gap, 0);
        depth[t] = 0;
        gap[0] = 1;
        cur[t] = head[t];
        queue<int> q;
        q.push(t);
        while (q.size()) {
            int u = q.front(); q.pop();
            for (int i = head[u]; i; i = e[i].next) {
                int v = e[i].to;
                if (depth[v] != -1) continue;
                q.push(v);
                depth[v] = depth[u] + 1;
                gap[depth[v]]++;
            }
        }
        return;
    }
    
    LL dfs(int now, LL minflow,int n) {
        if (now == t) {
            Maxflow += minflow;
            return minflow;
        }
        LL nowflow = 0;
        for (int i = cur[now]; i; i = e[i].next) {
            cur[now] = i;
            int v = e[i].to;
            if (e[i].w && depth[v] + 1 == depth[now]) {
                LL k = dfs(v, min(e[i].w, minflow - nowflow), n);
                if (k) {
                    e[i].w -= k;
                    e[i ^ 1].w += k;
                    nowflow += k;
                }
                if (minflow == nowflow) return nowflow;
            }
        }
        gap[depth[now]]--;
        if (!gap[depth[now]]) depth[s] = n + 1;
        depth[now]++;
        gap[depth[now]]++;
        return nowflow;
    }
    
    LL ISAP(int n) {
        Maxflow = 0;
        bfs();
        while (depth[s] < n) {
            memcpy(cur, head, sizeof(head));
            dfs(s, INF, n);
        }
        return Maxflow;
    }
    
    int main() {
        ios::sync_with_stdio(false);
        cin >> n >> m;
        s = n + 1; t = n + 2;
        cnt_e = 1;
        f(i, 1, n) {
            cin >> wish[i];
            if (!wish[i]) addn(cnt_e, head, e, s, i, 1);
            else addn(cnt_e, head, e, i, t, 1);
        }
        f(i, 1, m) {
            int u, v; cin >> u >> v;
            addn(cnt_e, head, e, u, v, 1);
            addn(cnt_e, head, e, v, u, 1);
        }
        cout << ISAP(n+2);
        return 0;
    }
    
  • 相关阅读:
    ESP8266 RTOS SDK烧写环境构建
    杂记:解决Android扫描BLE设备名称不刷新问题
    deviceMotion.userAcceleration加速度方向
    二、多功能提示框——MBProgressHUD
    一、初识CocoaPods——XCode的依赖库管理工具
    摄像机的控制
    DOTween 使用方法
    Unity依赖注入使用详解
    Unity中对SQL数据库的操作
    unity导弹算法 预计目标点
  • 原文地址:https://www.cnblogs.com/streamazure/p/13903335.html
Copyright © 2011-2022 走看看