UVA 10779 Collectors Problem

时间:2021-11-06 20:04:00

UVA 10779 Collectors Problem

我们考虑对所有徽章建一排点,然后从徽章连向 T 建立限制为 1 的边,然后从 S 到每种徽章建立我们拥有数量的点。

然后考虑对别人交换,从每种徽章连向没有这种徽章的人,容量限制是 1 ,再从每个人连向它拥有个数大于 1 的徽章,容量是它的徽章数 - 1。

这样建图跑最大流就做完啦。

#include "iostream"
#include "algorithm"
#include "cstring"
#include "cstdio"
#include "queue"
#include "cmath"
#include "vector"
using namespace std;
#define mem(a) memset( a , 0 , sizeof a )

class maxFlow {
public:
    typedef long long ll;
    std::queue<int> q;
    std::vector<int> head, cur, nxt, to, dep;
    std::vector<ll> cap;

    maxFlow(int _n = 0) { init(_n); }
    void init(int _n) {
        head.clear();
        head.resize(_n   1, 0);
        nxt.resize(2);
        to.resize(2);
        cap.resize(2);
    }
    void init() { init(head.size() - 1); }
    int add(int u, int v, ll w) {
        nxt.push_back(head[u]);
        int x = ( head[u] = to.size() );
        to.push_back(v);
        cap.push_back(w);
        return x;
    }
    int Add(int u, int v, ll w) {
//      printf("%d %d %dn",u,v,w);
        add(u, v, w);
        return add(v, u, 0);
    }
    void del(int x) { cap[x << 1] = cap[x << 1 | 1] = 0; }
    bool bfs(int s, int t, int delta) {
        dep.clear();
        dep.resize(head.size(), -1);
        dep[s] = 0;
        q.push(s);
        while (!q.empty()) {
            int u = q.front();
            q.pop();
            for (int i = head[u]; i; i = nxt[i]) {
                int v = to[i];
                ll w = cap[i];
                if (w >= delta && dep[v] == -1) {
                    dep[v] = dep[u]   1;
                    q.push(v);
                }
            }
        }
        return ~dep[t];
    }
    ll dfs(int u, ll flow, int t, int delta) {
        if (dep[u] == dep[t])
            return u == t ? flow : 0;
        ll out = 0;
        for (int& i = cur[u]; i; i = nxt[i]) {
            int v = to[i];
            ll w = cap[i];
            if (w >= delta && dep[v] == dep[u]   1) {
                ll f = dfs(v, std::min(w, flow - out), t, delta);
                cap[i] -= f;
                cap[i ^ 1]  = f;
                out  = f;
                if (out == flow)
                    return out;
            }
        }
        return out;
    }
    ll maxflow(int s, int t) {
        ll out = 0;
        ll maxcap = *max_element(cap.begin(), cap.end());
        for (ll delta = 1ll << int(log2(maxcap)   1e-12); delta; delta >>= 1) {
            while (bfs(s, t, delta)) {
                cur = head;
                out  = dfs(s, 0x7fffffffffffffffll, t, delta);
            }
        }
        return out;
    }
    ll getflow(int x) const { return cap[x << 1 | 1]; }
} F ;
int n , m , k , s = 200 , t = 201;
int c[26];
int main() {
    int T;cin >> T; int kase = 0;
    while( T-- ) {
        scanf("%d%d",&n,&m);
        F.init( 1000 );
        scanf("%d",&k);
        mem( c );
        for( int i = 1 , a ; i <= k ;    i ) scanf("%d",&a) ,    c[a];
        for( int i = 1 ; i <= m ;    i ) if( c[i] ) F.Add( s , i , c[i] );
        for( int i = 1 ; i <= m ;    i ) F.Add( i , t , 1 );
        for( int i = 2 ; i <= n ;    i ) {
            scanf("%d",&k); mem( c );
            for( int j = 1 , a ; j <= k ;    j ) scanf("%d",&a) ,    c[a];
            for( int j = 1 ; j <= m ;    j )
                if( c[j] > 1 ) F.Add( i   m , j , c[j] - 1 ); else if( !c[j] ) F.Add( j , i   m , 1 );
        }
        printf("Case #%d: %lldn",  kase,F.maxflow( s , t ));
    }
}