费用流 ZOJ 3933 Team Formation

 

题目链接

题意:两个队伍,有一些边相连,问最大组对数以及最多女生数量

分析:费用流模板题,设置两个超级源点和汇点,边的容量为1,费用为男生数量.建边不能重复建边否则会T.zkw费用流在稠密图跑得快,普通的最小费用最大流也能过,只是相对来说慢了点

#include <bits/stdc++.h>

const int N = 5e2 + 5;
const int INF = 0x3f3f3f3f;
struct Min_Cost_Max_Flow {
    struct Edge {
        int from, to, cap, flow, cost;
    };
    std::vector<Edge> edges;
    std::vector<int> G[N];
    bool vis[N];
    int d[N], p[N], a[N];
    int n, m;
    
    void init(int n) {
        this->n = n;
        for (int i=0; i<=n; ++i) {
            G[i].clear ();
        }
        edges.clear ();
    }
    void add_edge(int from, int to, int cap, int cost)    {
        edges.push_back ((Edge) {from, to, cap, 0, cost});
        edges.push_back ((Edge) {to, from, 0, 0, -cost});
        m = edges.size ();
        G[from].push_back (m - 2);
        G[to].push_back (m - 1);
    }
    bool SPFA(int s, int t, int &flow, int &cost) {
        memset (d, INF, sizeof (d));
        memset (vis, false, sizeof (vis));
        memset (p, -1, sizeof (p));
        d[s] = 0; vis[s] = true; p[s] = 0; a[s] = INF;

        std::queue<int> que; que.push (s);
        while (!que.empty ()) {
            int u = que.front (); que.pop ();
            vis[u] = false;
            for (int i=0; i<G[u].size (); ++i)   {
                Edge &e = edges[G[u][i]];
                if (e.cap > e.flow && d[e.to] > d[u] + e.cost)   {
                    d[e.to] = d[u] + e.cost;
                    p[e.to] = G[u][i];
                    a[e.to] = std::min (a[u], e.cap - e.flow);
                    if (!vis[e.to])    {
                        vis[e.to] = true;
                        que.push (e.to);
                    }
                }
            }
        }

        if (d[t] == INF) {
            return false;
        }
        flow += a[t];
        cost += d[t] * a[t];
        int u = t;
        while (u != s) {
            edges[p[u]].flow += a[t];
            edges[p[u]^1].flow -= a[t];
            u = edges[p[u]].from;
        }
        return true;
    }
    void run(int s, int t, int &flow, int &cost)    {
        flow = cost = 0;
        while (SPFA (s, t, flow, cost));
        
        printf ("%d %d\n", flow, 2 * flow - cost);
        for (int i=0; i<edges.size (); i+=2) {
            if (edges[i].from == s || edges[i].to == t || edges[i].flow == 0) {
                continue;
            }
            printf ("%d %d\n", edges[i].from, edges[i].to);
        }
    }   
};
Min_Cost_Max_Flow mcmf;
char group[N], sex[N];
bool list[N];
int n, m;

int main() {
    int T; scanf ("%d", &T);
    while (T--) {
        scanf ("%d", &n);
        scanf ("%s", group + 1);
        scanf ("%s", sex + 1);

        mcmf.init (n + 1);
        int s = 0, t = n + 1;
        for (int i=1; i<=n; ++i) {
            if (group[i] == '0') {
                mcmf.add_edge (s, i, 1, 0);
            } else {
                mcmf.add_edge (i, t, 1, 0);
            }
            int m; scanf ("%d", &m);
            memset (list, false, sizeof (list));
            for (int j=1; j<=m; ++j) {
                int v; scanf ("%d", &v);
                list[v] = true;
            }
            if (group[i] == '1') {
                continue;
            }
            int cost = (sex[i] == '1');
            for (int j=1; j<=n; ++j) {
                if (list[j] || group[i] == group[j]) {
                    continue;
                }
                mcmf.add_edge (i, j, 1, cost + (sex[j] == '1'));
            }
        }
        int flow, cost;
        mcmf.run (s, t, flow, cost);
    }

    return 0;
}

  

posted @ 2016-04-13 15:35  Running_Time  阅读(275)  评论(0编辑  收藏  举报