思想:缩点+sap
Max,t还可以缩小,优化,高数课写的,有点丑,暂时懒得改。
#include<cstdio>
#include<cstdlib>
#include<iostream>
#include<memory.h>
#include<algorithm>
#include<cstring>
#include<cmath>
using namespace std;
const int maxm=401000;
const int inf=0x7fffffff;
int vd[maxm],dis[maxm];
int Laxt[maxm],Next[maxm],To[maxm],V[maxm];
int n,m,cnt,ans,s,t;
int a[maxm],c[maxm];
void _update()
{
memset(Laxt,0,sizeof(Laxt));
memset(dis,0,sizeof(dis));
memset(vd,0,sizeof(vd));
memset(a,0,sizeof(a));
memset(c,0,sizeof(c));
cnt=2;
ans=0;
}
void _add(int u,int v,int c)
{
Next[cnt]=Laxt[u];
Laxt[u]=cnt;
To[cnt]=v;
V[cnt++]=c;
Next[cnt]=Laxt[v];
Laxt[v]=cnt;
To[cnt]=u;
V[cnt++]=0;
}
int _sap(int u,int flow)
{
int tmp,delta=0;
if(flow==0||u==t) return flow;
for(int i=Laxt[u];i;i=Next[i])
{
if(dis[To[i]]+1==dis[u]&&V[i]>0){
tmp=_sap(To[i],min(flow-delta,V[i]));
V[i]-=tmp;
V[i^1]+=tmp;
delta+=tmp;
if(delta==flow||dis[s]>t) return delta;
}
}
vd[dis[u]]--;
if(vd[dis[u]]==0) dis[s]=t+1;
vd[++dis[u]]++;
return delta;
}
int main()
{
int n,m,i,j,Max,x;
while(~scanf("%d%d",&n,&m))
{
_update();
Max=0;
for(i=1;i<=n;i++){
int tmp=0;
for(j=1;j<=m;j++) {
scanf("%d",&x);
tmp=tmp*2+x;
}
if(tmp>Max) Max=tmp;
a[tmp]++;
}
s=0;t=Max+m+1;
for(i=1;i<=m;i++) scanf("%d",&c[i]);
for(i=1;i<=Max;i++){
if(a[i]>0) {
_add(0,i,a[i]);
int k=m,p=i;
while(k&&p){
int tmp=p%2;
p/=2;
if(tmp>0) _add(i,Max+k,inf);
k--;
}
}
}
for(i=1;i<=m;i++) _add(Max+i,t,c[i]);
while(dis[s]<=t) {
ans+=_sap(s,inf);
}
if(ans==n) printf("YES
");
else printf("NO
");
}
return 0;
}