加超级源点和汇点的思想,并且利用二进制的特点把n个人划分到 1----1024 之间这样就能够划出每个人的特异性,由于在操作中开始是限定了起点的流量的,所以(i&num[j])则是不考虑限流的把这些人放回m个终点,再由m个终点汇聚到超级汇点.
参考模板:http://www.cnblogs.com/wally/archive/2013/05/03/3054778.html
#include <math.h>
#include <algorithm>
#include <iostream>
#include <queue>
#include <cstring>
#include <cstdio>
#include <list>
#include <deque>
#include <set>
#include <vector>
#include <map>
#define LL long long
#define max(a,b) (a>b?a:b)
using namespace std;
const int MAXN=1e5+100;
const int MAXM=4e6+100;
const int MAX=0x7fffffff;
struct node
{
int to,nex,val;
}edge[MAXN];
int level[MAXN];///标记层次
///间隙优化,定义gap[i]为标号是i的点的个数
///在重标记i时,检查gap[level[i]],若减为0,这算法结束。
int gap[MAXN];
int pre[MAXN];
int cur[MAXN];
int head[MAXN];
int NV,NE;///点 边
void inte()
{
NE=0;
memset(head,-1,sizeof(head));
}
///NE 记录边数
void addedge(int fr,int to,int val,int cap=0)
{
edge[NE].to=to;edge[NE].val=val;edge[NE].nex=head[fr];
head[fr]=NE++;///向边
edge[NE].to=fr;edge[NE].val=cap;edge[NE].nex=head[to];
head[to]=NE++;///反边
}
int sap(int start,int ed)
{
memset(level,0,sizeof(level));
memset(pre,-1,sizeof(pre));
memset(gap,0,sizeof(gap));
///cur保存的是当前弧
memcpy(cur,head,sizeof(head));
int u=pre[start]=start;//原点本身为前驱
int maxflow=0,aug=-1;
gap[0]=NV;
while(level[start]<NV)
{
loop:
for(int &i=cur[u];i!=-1;i=edge[i].nex)
{
//int now=edge[i].to;
int v=edge[i].to;
if(edge[i].val&&level[u]==level[v]+1)
{
if(aug==-1)
{
aug=edge[i].val;
}
else
{
aug=min(edge[i].val,aug);
}
pre[v]=u;
u=v;
if(v==ed)
{
maxflow+=aug;
for(u=pre[v];v!=start;v=u,u=pre[v])
{
edge[cur[u]].val-=aug;
edge[cur[u]+1].val+=aug;
}
aug=-1;
}
goto loop;
}
}
int minlevel=NV;
for(int i=head[u];i!=-1;i=edge[i].nex)
{
int v=edge[i].to;
if(edge[i].val&&minlevel>level[v])
{
cur[u]=i;///记录下有效边的位置
minlevel=level[v];
}
}
gap[level[u]]--;
if(gap[level[u]]==0)break;
level[u]=minlevel+1;
gap[level[u]]++;
u=pre[u];
}
return maxflow;
}
int cnt[MAXN]={0};
int num[13];
int main()
{
ios::sync_with_stdio(false);
int n,m;
num[0]=1;
for(int i=1;i<=10;i++)
{
num[i]=num[i-1]*2;
}
while(cin>>n>>m)
{
inte();
memset(cnt,0,sizeof(cnt));
//NV=m;
NV=1024+m+2;
int fr,to,val;
for(int i=0;i<n;i++)
{
int tmp=0;
for(int j=0;j<m;j++)
{
cin>>val;
if(val)//cnt[i*num[j]]++;
{
tmp+=val*num[j];
}
}
cnt[tmp]++;
}
for(int i=0;i<1024;i++)
{
if(cnt[i]==0)continue;
addedge(0,i+1,cnt[i]);
for(int j=0;j<10;j++)
{
/* if(i&num[j])
{
cout<<"cnt= "<<cnt[i]<<endl;
cout<<"i= "<<i<<" num[j]= "<<num[j]<<endl;
}*/
if(i&num[j])addedge(i+1,1024+j+1,MAXM);//把1024条边不限量的还回m个汇点
}
}
for(int i=1;i<=m;i++)//把m个汇点汇到超级汇点1024+m+1处
{
cin>>val;//num[i];
addedge(1024+i,1024+m+1,val);
}
/*
for(int i=1;i<=m;i++)
{
if(cnt[i]!=0)addedge(0,i,cnt[i]);
}*/
int ans=sap(0,1024+m+1);//起点为0
// cout<<ans<<endl;
if(ans==n)
cout<<"YES"<<endl;
else cout<<"NO"<<endl;
}
return 0;
}