又一次在比赛中碰到网络流,又一次没有搞出来,剁手啊!!!
刚开始队友跟我说这题像是网络流,但我想了想,觉得最大流不能保证每个比赛节点都能满流,所以。。。。。
赛后队友想到了可以用二进制枚举当前选取的比赛。这时我才顿悟。。。用网络流。。。根据选取的比赛建二分图,左边节点为题目节点,而每次只需把当前枚举的比赛加到右边节点中!这样的话,只要所有右边节点能满流,就说明当前枚举策略可行!时间复杂度2^15*(max_flow()),好暴力。。。不过在bnuoj上444ms过,爽爽的。。。
#include<iostream> #include<algorithm> #include<vector> #include<string> #include<stack> #include<queue> #include<map> #include<set> #include<cstdio> #include<cstring> #include<cmath> #include<sstream> #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 LL long long #define PB push_back using namespace std; const int maxn = 1111; const int INF = 100000000; struct Edge { int from, to, cap, flow; }; int n, m, a[maxn], s, t; map<string, int> mp; vector<int> pro[maxn]; vector<Edge> edges; vector<int> G[maxn]; bool vis[maxn]; int d[maxn], cur[maxn]; void init() { s = 0, t = n + m + 1; REP(i, maxn) 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 tmp = edges.size(); G[from].PB(tmp-2); G[to].PB(tmp-1); } bool bfs() { CLR(vis, 0); vis[s] = 1, d[s] = 0; queue<int> q; q.push(s); while(!q.empty()) { int x = q.front(); q.pop(); for(int i=0; i<G[x].size(); i++) { 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; for(int& i=cur[x]; i<G[x].size(); i++) { Edge& e = edges[G[x][i]]; if(d[e.to] == d[x]+1 && (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 kase = 1; char str[1111111], tmp[111]; while(scanf("%d%d", &n, &m), n+m) { mp.clear(); REP(i, n+1) pro[i].clear(); FF(i, 1, n+1) { scanf("%s%d", tmp, &a[i]); mp[tmp] = i; } gets(str); FF(i, 1, m+1) { gets(str); istringstream in(str); while(in >> tmp) pro[mp[tmp]].PB(i); } int ans = 0; FF(f, 1,(1<<n)) { int cnt = 0, sum = 0; init(); REP(i, n) if(f & (1<<i)) { sum += a[i+1], cnt++; add(i+m+1, t, a[i+1]); } if(sum > m) continue; if(cnt < ans) continue; FF(i, 1, m+1) add(s, i, 1); REP(i, n) { if(f && (1<<i)) for(int j=0; j<pro[i+1].size(); j++) { int v = pro[i+1][j]; add(v, i+m+1, 1); } } if(max_flow() == sum) ans = cnt; } printf("Case #%d: %d\n", kase++, ans); } return 0; }