题目链接:Click here~~
题意:
有 n 个人选择 m 个星球居住,选择情况和星球居住上限有限制,问是否能全部满足要求。
解题思路:
解法一:
开始想到了最裸的建图,果然 TLE 了。
由于 n 太大(1e5) m 很小(10),所以我们可以进行状态压缩,将 n 个人等价划分成 1 << m 个集合,记录下各个集合有多少人。
建边:S -> mask,cap = cnt[mask] ; mask -> planet of mask,cap = inf;planet -> T,cap = limit of planet。
#include <queue> #include <stdio.h> #include <string.h> #include <algorithm> const int inf = 0x3fffffff; using namespace std; #define CLR(a,v) memset(a,v,sizeof(a)) template<int N,int M> struct Isap{ int top,s,t,d[N],pre[N],cur[N],gap[N]; struct Vertex{ int head; }V[N]; struct Edge{ int v,next; int c,f; }E[M]; inline void init(){ CLR(V,-1); top = 0; } inline void set_st(int _s,int _t){ s = _s , t = _t; } inline void add_edge(int u,int v,int c){ E[top].v = v; E[top].c = c;E[top].f = 0; E[top].next = V[u].head; V[u].head = top++; } inline void add(int u,int v,int c){ add_edge(u,v,c); add_edge(v,u,0); } inline void set_d(){ CLR(d,-1);CLR(gap,0); queue<int> Q; d[t] = 0; Q.push(t); while(!Q.empty()){ int v = Q.front(); Q.pop(); ++gap[ d[v] ]; for(int i=V[v].head;~i;i=E[i].next){ int u = E[i].v; if(d[u] == -1){ d[u] = d[v] + 1; Q.push(u); } } } } int sap(int n){ //n vertexs set_d(); int ans = 0, u = s, flow = inf; memcpy(cur,V,sizeof(V)); while(d[s] < n){ int &i = cur[u]; for(;~i;i=E[i].next){ int v = E[i].v; if(E[i].c>E[i].f && d[u]==d[v]+1){ u = v; pre[v] = i; flow = min(flow,E[i].c-E[i].f); if(u == t){ while(u != s){ int j = pre[u]; E[j].f += flow; E[j^1].f -= flow; u = E[j^1].v; } ans += flow; flow = inf; } break; } } if(i == -1){ if(--gap[ d[u] ] == 0) break; int dmin = n - 1; cur[u] = V[u].head; for(int j=V[u].head;~j;j=E[j].next) if(E[j].c > E[j].f) dmin = min(dmin,d[ E[j].v ]); d[u] = dmin + 1; ++gap[ d[u] ]; if(u != s) u = E[ pre[u]^1 ].v; } } return ans; } }; const int N = 1<<10 | 25; Isap<N,N*11*2+5> g; int cnt[1<<10]; inline void In(int& res) { int c; while((c = getchar())<'0' || c>'9'); res = c-'0'; while((c = getchar())>='0' && c<='9') res = res*10 + c-'0'; } int main() { int n,m; while(~scanf("%d%d",&n,&m)) { CLR(cnt,0); g.init(); for(int i=1;i<=n;i++) { int mask = 0; for(int j=0;j<m;j++) { int can; //scanf("%d",&can); In(can); if(can) mask |= 1 << j; } cnt[mask]++; } int nn = n; n = 1 << m; for(int mask=1;mask<n;mask++) if(cnt[mask]) { g.add(0,mask,cnt[mask]); for(int j=0;j<m;j++) if(mask & (1 << j)) g.add(mask,n+j,inf); } for(int i=0;i<m;i++) { int cap; //scanf("%d",&cap); In(cap); if(cap) g.add(n+i,n+m,cap); } g.set_st(0,n+m); int ans = cnt[0] ? 0 : g.sap(n+m+1); puts(ans==nn?"YES":"NO"); } return 0; }
#include <vector> #include <stdio.h> #include <string.h> #include <algorithm> using namespace std; const int N = 1e5 + 5; const int M = 12; bool g[N][M],vis[M]; int n,m,match[M][N],cap[M],cnt[M]; bool dfs(int u) { for(int v=1;v<=m;v++) { if(!vis[v] && g[u][v]) { vis[v] = true; if(cnt[v] < cap[v]) { match[v][ ++cnt[v] ] = u; return true; } else { for(int i=1;i<=cap[v];i++) { if(dfs(match[v][i])) { match[v][i] = u; return true; } } } } } return false; } int maxMatch(int n) { memset(match,0,sizeof(match)); memset(cnt,0,sizeof(cnt)); int ans = 0; for(int i=1;i<=n;i++) { memset(vis,false,sizeof(vis)); if(dfs(i)) ++ans; else return 0; } return ans; } inline void In(int& res) { int c; while((c = getchar())<'0' || c>'9'); res = c-'0'; while((c = getchar())>='0' && c<='9') res = res*10 + c-'0'; } int main() { while(~scanf("%d%d",&n,&m)) { memset(g,false,sizeof(g)); for(int i=1;i<=n;i++) { for(int j=1;j<=m;j++) { int can; //scanf("%d",&can); In(can); g[i][j] = can; } } for(int i=1;i<=m;i++) { //scanf("%d",&cap); In(cap[i]); } puts(maxMatch(n)==n?"YES":"NO"); } return 0; }