题目链接: Escape HDU - 3605
题目大意
n个人, m个星球( 1≤n≤105,1≤m≤10 ), 每个人适应某些星球, 不适应其他星球, 每个星球有人口限制, 问是否所有人都可以移民
思路
最大流
但是数据规模太大, 如果直接建图会超时
但是星球数量只有10个, 我们可以把人根据最每个星球的适应情况进行分类, 用二进制进行状态压缩, 这样最多分成
210
种人
把每类人与其所能适应的星球连边, 容量为INF
S与每类人连边, 容量为这类人的人数
每个星球与T连边, 容量为星球容量
代码
#include <iostream>
#include <algorithm>
#include <cstdio>
#include <cstring>
#include <queue>
#include <vector>
#include <map>
using namespace std;
const int MAXV = 3000, INF = 0X3F3F3F3F;
struct edge
{
int to, cap, rev;
edge(int a, int b, int c) :to(a), cap(b), rev(c){}
};
vector<edge> G[MAXV];
int iter[MAXV], level[MAXV], S, T;
void add_edge(int from, int to, int cap)
{
G[from].push_back(edge(to, cap, G[to].size()));
G[to].push_back(edge(from, 0, G[from].size()-1));
}
bool bfs()
{
memset(level, -1, sizeof(level));
level[S] = 0;
queue<int> que;
que.push(S);
while(!que.empty())
{
int v = que.front(); que.pop();
for(int i=0; i<(int)G[v].size(); ++i)
{
edge &e = G[v][i];
if(e.cap>0 && level[e.to]==-1)
{
level[e.to] = level[v] + 1;
que.push(e.to);
}
}
}
return level[T]!=-1;
}
int dfs(int v, int f)
{
if(v == T) return f;
for(int &i=iter[v]; i<(int)G[v].size(); ++i)
{
edge &e = G[v][i];
if(e.cap>0 && level[e.to]>level[v])
{
int d = dfs(e.to, min(f, e.cap));
if(d)
{
e.cap -= d;
G[e.to][e.rev].cap+= d;
return d;
}
}
}
return 0;
}
int max_flow()
{
int flow = 0;
while(bfs())
{
memset(iter, 0, sizeof(iter));
int f;
while((f=dfs(S, INF))) flow += f;
}
return flow;
}
void init()
{
for(int i=0; i<MAXV; ++i) G[i].clear();
}
int n, m, a[1<<11], b[20];
int main()
{
while(scanf("%d%d", &n, &m) == 2)
{
memset(a, 0, sizeof(a));
for(int i=0; i<n; ++i)
{
int s = 0, x;
for(int j=0; j<m; ++j)
{
scanf("%d", &x);
if(x) s+=(1<<j);
}
a[s]++;
}
int nn = 1<<m;
for(int i=0; i<m; ++i) scanf("%d", &b[i]);
init();
S = nn + m;
T = S + 1;
for(int i=0; i<nn; ++i)
{
if(a[i])
{
add_edge(S, i, a[i]);
}
for(int j=0; j<m; ++j)
{
if(i & (1<<j)) add_edge(i, j+nn, INF);
}
}
for(int i=0; i<m; ++i) add_edge(i+nn, T, b[i]);
if(n == max_flow()) puts("YES");
else puts("NO");
}
return 0;
}