很明显的一个二分图多重匹配,一开始用网络流直接建图,悲剧的TLE了
之后,看了网上解释,缩点,确实大大简化了问题,也就可以AC了,600+ms
一开始是这样建图的,先有虚拟源点s,汇点t,从s向每一个人连一条容量为1的边,每一个人向他适合的每一个planet连一条容量为1边,再从每一个planet连一条容量为w[i](该planet的容量)的边,很明显,判断最大流是否等于n即可。n为100000,而m只有10
其实,在这道题目里面,人是无差别的,有区别是他们各自的选择,而总共只有10个planet,也就是所有的选择数也就(1<<10)种,所有选择都相同的人完全是等价的!!!
可是,没想到还可以优化一下IO,突然刷到100+ms了,ORZ
也可以匈牙利算法做,优化IO之后,171ms,也不慢,而且代码十分简单
匈牙利算法
#include<iostream> #include<string> using namespace std; const int N = 100002; int cap[12],map[N][12],vlink[12],link[12][N]; bool vis[12]; int n,m; int in() { char ch; int a = 0; while((ch = getchar()) == ' ' || ch == '\n'); a += ch - '0'; while((ch = getchar()) != ' ' && ch != '\n') { a *= 10; a += ch - '0'; } return a; } int path(int s) { for(int i=0;i<m;i++) { if(map[s][i] && !vis[i]) { vis[i]=true; if(vlink[i]<cap[i]) { link[i][vlink[i]++]=s; return 1; } for(int j=0;j<vlink[i];j++) { if(path(link[i][j])) { link[i][j]=s; return 1; } } } } return 0; } int main() { while(scanf("%d %d",&n,&m)==2) { for(int i=0;i<n;i++) for(int j=0;j<m;j++) map[i][j]=in(); for(int i=0;i<m;i++) scanf("%d",&cap[i]); memset(vlink,0,sizeof(vlink)); bool flag=true; for(int i=0;i<n;i++) { memset(vis,false,sizeof(vis)); if(!path(i)) { flag=false; break; } } if(flag) puts("YES"); else puts("NO"); } return 0; }
最大流+缩点
#include<iostream> #include<algorithm> #include<string> using namespace std; const int N = 120000+20; int n; int size,head[N],dis[N],gap[N],pre[N],cur[N]; int mm[(1<<12)]; struct edge { int v,w,next; edge(){} edge(int v,int next,int w=0):v(v),next(next),w(w){} }E[N*30]; inline void insert(int u,int v,int w) { E[size]=edge(v,head[u],w); head[u]=size++; E[size]=edge(u,head[v],0); head[v]=size++; } int ISAP(int src,int des) { int maxflow=0; memset(dis,0,sizeof(dis)); memset(gap,0,sizeof(gap)); for(int i=0;i<=n;i++) cur[i]=head[i]; int u =pre[src]=src; int aug=-1; while(dis[src]<n) { loop: for(int &i=cur[u];i!=-1;i=E[i].next) { int v=E[i].v; if(E[i].w && dis[u]==dis[v]+1) { aug=min(aug,E[i].w); pre[v]=u; u=v; if(v==des) { maxflow+=aug; for(u=pre[u];v!=src;v=u,u=pre[u]) { E[cur[u]].w-=aug; E[cur[u]^1].w+=aug; } aug=INT_MAX; } goto loop; } } int mdis=n; for(int i=head[u];i!=-1;i=E[i].next) { int v=E[i].v; if(E[i].w && mdis>dis[v]) { cur[u]=i; mdis=dis[v]; } } if((--gap[dis[u]])==0) break; gap[dis[u]=mdis+1]++; u=pre[u]; } return maxflow; } int in() { char ch; int a = 0; while((ch = getchar()) == ' ' || ch == '\n'); a += ch - '0'; while((ch = getchar()) != ' ' && ch != '\n') { a *= 10; a += ch - '0'; } return a; } int main() { int m,a,b; while(scanf("%d %d",&n,&m)==2) { size=0; memset(head,-1,sizeof(head)); memset(mm,0,sizeof(mm)); for(int i=0;i<n;i++) { int t=0; for(int j=0;j<m;j++) { a=in(); if(a) t|=(1<<j); } mm[t]++; } int nn=(1<<m),s=1,T=nn+m+2; int n1=n; n=T; for(int i=1;i<nn;i++) { if(mm[i]==0) continue; insert(s,i+2,mm[i]); for(int j=0;j<m;j++) { if(i&(1<<j)) insert(i+2,j+nn+2,mm[i]); } } for(int i=0;i<m;i++) { scanf("%d",&b); insert(i+nn+2,T,b); } if(ISAP(s,T)>=n1) puts("YES"); else puts("NO"); } return 0; }