状态压缩+最大流
因为最多只有10个星球,所以人最多只有1<<10种。所以按照人的种类来建图。
此题有毒,光是输入就TLE了,联系了HDU OJ管理员胡杰,把时间放宽为2000ms,最终,用了输入挂,用了C++提交,1200ms过了;不用输入挂 用C++ 1700ms。
#include<cstdio> #include<cstring> #include<string> #include<cmath> #include<vector> #include<queue> #include<algorithm> using namespace std; const int maxn = 1500 + 10; const int INF = 0x7FFFFFFF; struct Edge { int from, to, cap, flow; }; vector<Edge>edges; vector<int>G[maxn]; bool vis[maxn]; int d[maxn]; int cur[maxn]; int n, m, s, t; int Scan() { int res = 0, ch, flag = 0; if ((ch = getchar()) == '-') //判断正负 flag = 1; else if (ch >= '0' && ch <= '9') //得到完整的数 res = ch - '0'; while ((ch = getchar()) >= '0' && ch <= '9') res = res * 10 + ch - '0'; return flag ? -res : res; } //求出层次网络 bool BFS() { memset(vis, 0, sizeof(vis)); queue<int>Q; Q.push(s); d[s] = 0; vis[s] = 1; 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]; } //加边 void AddEdge(int from, int to, int cap) { Edge r; r.from = from; r.to = to; r.cap = cap; r.flow = 0; edges.push_back(r); Edge d; d.from = to; d.to = from; d.cap = 0; d.flow = 0; edges.push_back(d); m = edges.size(); G[from].push_back(m - 2); G[to].push_back(m - 1); } //每个阶段来一次DFS增广 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[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 Maxflow(int ss, int tt) { int flow = 0; while (BFS()) { memset(cur, 0, sizeof(cur)); flow += DFS(ss, INF); } return flow; } int N, M; int Tot[maxn]; int Er[maxn]; int zh[maxn]; int ZH[maxn]; int main() { while (scanf("%d%d", &N, &M) != EOF) { edges.clear(); for (int i = 0; i<maxn; i++) G[i].clear(); memset(Tot, 0, sizeof Tot); for (int i = 1; i <= N; i++) { int Ans = 0; for (int j = 0; j < M; j++) Er[j] = Scan(); for (int j = 0; j<M; j++) Ans = Ans + Er[j] * pow(2.0,j); Tot[Ans]++; } s = 1401; t = 1400; for (int i = 0; i <= (1<<10); i++) { if (Tot[i]) { AddEdge(s, i, Tot[i]); int y = i, q = 0, d = 0; while (y) zh[q] = y % 2, y = y / 2, q++; for (int ii = 0; ii<q; ii++) if (zh[ii]) AddEdge(i, 1100 + ii, INF); } } for (int i = 0; i<M; i++) { int x; x = Scan(); AddEdge(1100 + i, t, x); } int FF = Maxflow(s, t); if (FF != N) printf("NO "); else printf("YES "); } return 0; }