這個題是很難往網絡流上面構思的。。。
從s向每個物品增加容量為Bob擁有數的弧,然後從每個物品向t增加容量為1的弧(代表種類個數)。這時候跑最大流的話,得到的肯定是Bob擁有的初始種類數。那麼交換後的最大數呢?
對於Bob以外的小伙伴,如果i擁有j物品超過1個(交換後他自己至少保留一個),從人節點i向物品節點j增加容量為num-1的弧,表示他能輸出多少物品,而如果i沒有j物品,那麼從物品節點j向人節點i增加容量為1的弧(他最多接受1單位的物品)。然後跑最大流得到的就是答案了。
#include<algorithm> #include<iostream> #include<cstring> #include<cstdlib> #include<fstream> #include<sstream> #include<bitset> #include<vector> #include<string> #include<cstdio> #include<cmath> #include<stack> #include<queue> #include<stack> #include<map> #include<set> #define FF(i, a, b) for(int i=a; i<b; i++) #define FD(i, a, b) for(int i=a; i>=b; i--) #define REP(i, n) for(int i=0; i<n; i++) #define CLR(a, b) memset(a, b, sizeof(a)) #define debug puts("**debug**") #define LL long long #define PB push_back using namespace std; const int maxn = 300; const int INF = 1e9; int n, m, s, t, num[11][30]; int d[maxn], cur[maxn]; bool vis[maxn]; struct Edge { int from, to, cap, flow; }; vector<Edge> edges; vector<int> G[maxn]; void init() { s = 0, t = n + m + 1; CLR(num, 0); REP(i, t+1) G[i].clear(); edges.clear(); } void add(int from, int to, int cap) { edges.PB((Edge){from, to, cap, 0}); edges.PB((Edge){to, from, 0, 0}); int nc = edges.size(); G[from].PB(nc-2); G[to].PB(nc-1); } bool bfs() { CLR(vis, 0); queue<int> q; q.push(s); d[s] = 0, vis[s] = 1; while(!q.empty()) { int x = q.front(); q.pop(); int nc = G[x].size(); REP(i, nc) { Edge e = edges[G[x][i]]; if(!vis[e.to] && e.cap > e.flow) { vis[e.to] = 1; d[e.to] = d[x] + 1; q.push(e.to); } } } return vis[t]; } int dfs(int x, int a) { if(x == t || a == 0) return a; int flow = 0, f, nc = G[x].size(); for(int& i = cur[x]; i<nc; i++) { Edge& e = edges[G[x][i]]; if(d[x] + 1 == d[e.to] && (f = dfs(e.to, min(a, e.cap - e.flow))) > 0) { e.flow += f; edges[G[x][i]^1].flow -= f; flow += f; a -= f; if(a == 0) break; } } return flow; } int max_flow() { int flow = 0; while(bfs()) { CLR(cur, 0); flow += dfs(s, INF); } return flow; } int main() { int T; scanf("%d", &T); FF(kase, 1, T+1) { scanf("%d%d", &n, &m); init(); int x; REP(i, n) { scanf("%d", &num[i][0]); while(num[i][0]--) { scanf("%d", &x); num[i][x]++; } } FF(i, 1, m+1) { if(num[0][i]) add(s, i+n, num[0][i]); add(i+n, t, 1); } FF(i, 1, n) { FF(j, 1, m+1) { if(num[i][j] > 1) add(i, j+n, num[i][j] - 1); if(num[i][j] == 0) add(j+n, i, 1); } } printf("Case #%d: %d\n", kase, max_flow()); } return 0; }