题意:给n个人m个星球,每个人适不适合去某个星球,每个星球的最大容量,看能不能满足所有人能去一个星球
题解:可以看出如果直接建边,边的个数是1e5左右的,这样时间肯定会爆掉,那么我们考虑用二进制状态压缩,对于能去相同的星球的全部压缩成一个点,和星球连边,权值为能去的个数,然后这样就只有(1<<10)个左右,(其实是队友想出来的做法= =),星球连向汇点,权值为星球容量,然后跑最大流就好了
#include<bits/stdc++.h> #define fi first #define se second #define mp make_pair #define pb push_back #define pii pair<int,int> #define C 0.5772156649 #define pi acos(-1.0) #define ll long long #define mod 20090717 #define ls l,m,rt<<1 #define rs m+1,r,rt<<1|1 using namespace std; const double g=10.0,eps=1e-12; const int N=2005+10,maxn=80000+10,inf=0x3f3f3f; struct edge{ int to,Next,c; }e[maxn]; int s,t,cnt,head[N],dis[N]; int num[N]; void add(int u,int v,int c) { e[cnt].to=v; e[cnt].c=c; e[cnt].Next=head[u]; head[u]=cnt++; e[cnt].to=u; e[cnt].c=0; e[cnt].Next=head[v]; head[v]=cnt++; } bool bfs() { memset(dis,-1,sizeof dis); dis[s]=1; queue<int>q; q.push(s); while(!q.empty()) { int x=q.front(); q.pop(); for(int i=head[x];~i;i=e[i].Next) { int te=e[i].to; if(dis[te]==-1&&e[i].c>0) { dis[te]=dis[x]+1; q.push(te); } } } return dis[t]!=-1; } int dfs(int x,int mx) { if(x==t)return mx; int flow=0; for(int i=head[x];~i;i=e[i].Next) { int te=e[i].to,f; if(dis[te]==dis[x]+1&&e[i].c>0&&(f=dfs(te,min(mx-flow,e[i].c)))) { e[i].c-=f; e[i^1].c+=f; flow+=f; } } if(!flow)dis[x]=-2; return flow; } int max_flow() { int ans=0,f; while(bfs()) { while((f=dfs(s,inf)))ans+=f; } return ans; } void init() { memset(head,-1,sizeof head); memset(num,0,sizeof(num)); cnt=0; } int main() { /*ios::sync_with_stdio(false); cin.tie(0);*/ int n,m; while(~scanf("%d%d",&n,&m)) { init(); s=2000,t=2001; for(int i=1;i<=n;i++) { int q=0; for(int j=0;j<m;j++) { int a; scanf("%d",&a); q+=a*(1<<j); } num[q]++; } for(int i=1;i<1024;i++)add(s,i,num[i]); for(int i=1;i<1024;i++) { for(int j=0;j<=9;j++) { //if(i==463)printf("%d** ",j); if((i>>j)&1) add(i,1023+j+1,inf); } } for(int j=1;j<=m;j++) { int a; scanf("%d",&a); add(1023+j,t,a); } if(max_flow()==n)puts("YES"); else puts("NO"); } return 0; } /******************** 1,2,3,4,5,6,9,18 ********************/