Escape
Time Limit: 4000/2000 MS (Java/Others) Memory Limit: 65536/65536 K (Java/Others)Total Submission(s): 9652 Accepted Submission(s): 2295
Problem Description
2012 If this is the end of the world how to do? I do not know how. But now scientists have found that some stars, who can live, but some people do not fit to live some of the planet. Now scientists want your help, is to determine what all of people can live in these planets.
Input
More set of test data, the beginning of each data is n (1 <= n <= 100000), m (1 <= m <= 10) n indicate there n people on the earth, m representatives m planet, planet and people labels are from 0. Here are n lines, each line represents a suitable living conditions of people, each row has m digits, the ith digits is 1, said that a person is fit to live in the ith-planet, or is 0 for this person is not suitable for living in the ith planet.
The last line has m digits, the ith digit ai indicates the ith planet can contain ai people most..
0 <= ai <= 100000
The last line has m digits, the ith digit ai indicates the ith planet can contain ai people most..
0 <= ai <= 100000
Output
Determine whether all people can live up to these stars
If you can output YES, otherwise output NO.
If you can output YES, otherwise output NO.
Sample Input
1 1 1 1 2 2 1 0 1 0 1 1
Sample Output
YES NO
Source
2010 ACM-ICPC Multi-University Training Contest(17)——Host by ZSTU
题意:现在地球有n(<=100w)人数要去m(<=10)个其他星球生存,接下来n行每行m列,如果第i 为 1 对应这个人可去星球 i ,第 i 个星球最多可容ai个人(最后一行给出m个数)。现在问是否所有的人都可以到其他星球生存。
解题:最大流SAP。建图:因为人数多,而去星球的状态少最多是1024种,所以可以把每种状态看作是点,源点与每种状态连接一条边,容量为当前状态的人数,再每种状态与相应的星球连边,边容为当前状态的人数。再每个星球与汇点连边,边容为星球能容纳的人数。
ISAP算法还不懂的戳这里:http://www.renfei.org/blog/isap.html
#include<iostream>
#include<algorithm>
#include<cstring>
#include<cstdio>
#include<vector>
#include<queue>
#include<set>
#include<map>
using namespace std;
#define PI acos(-1.0)
#define eps 1e-8
#define ll long long
#define MEM(a, b) memset(a, b, sizeof(a))
#define pb push_back
#define mp make_pair
#define MII map<int,int>::iterator
#define MLL map<LL,LL>::iterator
#define pii pair<int,int>
#define SI set<int>::iterator
#define SL set<LL>::iterator
#define dug printf("bug-------bug-------bug\n");
using namespace std;
const int MAXN = 1030;
const int MAXM = 14000;
const int INF = 1 << 30;
int head[MAXN], eid;
int d[MAXN], cur[MAXN], pre[MAXN], gap[MAXN];
int source, sink, nv;
inline void init()
{
eid = 0;
memset(head, -1, sizeof(head));
}
struct Edge
{
int to, cap, nxt;
Edge(){}
Edge(int t, int c, int nx):to(t), cap(c), nxt(nx){}
}edge[MAXM];
void AddEdge(int u, int v, int c)
{
edge[eid].to = v;
edge[eid].cap = c;
edge[eid].nxt = head[u];
head[u] = eid++;
edge[eid].to = u;
edge[eid].cap = 0;
edge[eid].nxt = head[v];
head[v] = eid++;
}
void rev_bfs()
{
memset(gap, 0, sizeof(gap));
memset(d, -1, sizeof(d));
d[sink] = 0;
queue<int> q;
q.push(sink);
while(!q.empty())
{
int u = q.front();
q.pop();
for(int i = head[u]; i != -1; i = edge[i].nxt)
{
int v = edge[i].to;
if(d[v] != -1)
continue;
d[v] = d[u] + 1;
q.push(v);
gap[d[v]]++;
}
}
}
int ISAP()
{
memcpy(cur, head, sizeof(cur));//复制,当前弧优化
rev_bfs();
int flow = 0, u = pre[source] = source;
while(d[sink] < nv)
{
if(u == sink)//如果已经找到了一条增广路,则沿着增广路修改流量
{
int f = INF, neck;
for(int i = source; i != sink; i = edge[cur[i]].to)
if(f > edge[cur[i]].cap)
{
f = edge[cur[i]].cap;//不断更新需要减少的流量
neck = i;//记录回退点,目的是为了不用再回到起点重新找
}
for(int i = source; i != sink; i = edge[cur[i]].to)//修改流量
{
edge[cur[i]].cap -= f;
edge[cur[i]^1].cap += f;
}
flow += f;//更新
u = neck;//回退
}
int i;
for(i = cur[u]; i != -1; i = edge[i].nxt)
if(d[edge[i].to] + 1 == d[u] && edge[i].cap)
break;
if(i != -1)
{
cur[u] = i;//如果存在可行增广路,更新
pre[edge[i].to] = u;//修改当前弧
u = edge[i].to;
}
else//否则回退,重新找增广路
{
if((--gap[d[u]]) == 0)//GAP间隙优化,如果出现断层,可以知道一定不会再有增广路了
break;
int mind = nv;
for(i = head[u]; i != -1; i = edge[i].nxt)
{
if(edge[i].cap && mind > d[edge[i].to])//寻找可以增广的最小标号
{
cur[u] = i;//修改当前弧
mind = d[edge[i].to];
}
}
d[u] = mind + 1;
gap[d[u]]++;
u = pre[u];
}
}
return flow;
}
int main()
{
int n, m, s, t, ans, k[1030];
while(scanf("%d%d", &n, &m) != EOF)
{
memset(k, 0, sizeof(k));
int id = 0;
for(int i = 0; i < n; i++)
{
int state = 0, choose;
for(int j = 0; j < m; j++)
{
scanf("%d", &choose);
if(choose)
state |= 1 << j;
}
if(k[state] == 0 && state)
id++;
k[state]++;
}
ans = n;
init();
n = id;
source = 0, sink = n + m + 1, nv = n + m + 1;
for(int i = (1<<m)-1; i > 0; i--)
{
if(k[i] > 0)
{
AddEdge(source, id, k[i]);
for(int j = 0; (1<<j) <= i; j++)
if(i&(1<<j))
AddEdge(id, j+n+1, k[i]);
id--;
}
}
for(int j = 0; j < m; j++)
{
int star_live;
scanf("%d", &star_live);
if(star_live)
AddEdge(j+n+1, sink, star_live);
}
ans -= ISAP();
if(ans)
puts("NO");
else
puts("YES");
}
return 0;
}