#include<stdio.h>
#include<string.h>
#include<queue>
#include<math.h>
#include<algorithm>
using namespace std;
const int MAXN = 1110;
const int oo = 1e9+7;
struct Edge{int u, v, flow, next;}edge[MAXN*100];
int Head[MAXN], cnt;
int used[MAXN], cur[MAXN], Stack[MAXN];
int Layer[MAXN], gap[MAXN], cntv;///节点的总个数
void InIt()
{
cnt = 0;
memset(Head, -1, sizeof(Head));
memset(used, 0, sizeof(used));
}
void AddEdge(int u, int v, int flow)
{
edge[cnt].u = u;
edge[cnt].v = v;
edge[cnt].flow = flow;
edge[cnt].next = Head[u];
Head[u] = cnt++;
edge[cnt].u = v;
edge[cnt].v = u;
edge[cnt].flow = 0;
edge[cnt].next = Head[v];
Head[v] = cnt++;
}
void BFS(int End)
{
memset(Layer, -1, sizeof(Layer));
memset(gap, 0, sizeof(gap));
queue<int> Q;
Q.push(End);
Layer[End] = 0, gap[0] = 1;
while(Q.size())
{
int u = Q.front();
Q.pop();
for(int j=Head[u]; j!=-1; j=edge[j].next)
{
int v = edge[j].v;
if(Layer[v] == -1)
{
Layer[v] = Layer[u] + 1;
gap[Layer[v]]++;
Q.push(v);
}
}
}
}
int SAP(int start, int End)
{
int j, top=0, u = start, MaxFlow=0;
BFS(End);
cntv = End;
memcpy(cur, Head, sizeof(Head));
while(Layer[start] < cntv)
{///源点的层次小于总结点数,汇点是0层
if(u == End)
{
int MinFlow = oo, location;///记录下最小流量边的位置,出栈时候用
for(j=0; j<top; j++)
{
int i = Stack[j];
if(MinFlow > edge[i].flow)
{
MinFlow = edge[i].flow;
location = j;
}
}
for(j=0; j<top; j++)
{///所有的边减去路径上的最小流量
int i = Stack[j];
edge[i].flow -= MinFlow;
edge[i^1].flow += MinFlow;
}
MaxFlow += MinFlow;
top = location;///退栈
u = edge[Stack[top]].u;
}
else if(gap[Layer[u]-1] == 0)
break;///u所在的层下面的层没有了,出现了断层,也就没有了可行弧
for(j=cur[u]; j!=-1; j=edge[j].next)
{///如果u有可行弧就停止
if(Layer[u]==Layer[edge[j].v]+1 && edge[j].flow)
break;
}
if(j != -1)
{///找到了可行弧
cur[u] = j;///u点的可行弧是j
Stack[top++] = j;///记录下这条边
u = edge[j].v;
}
else
{///没有找到可行弧,修改标号
int MinIndex = cntv;
for(j=Head[u]; j!=-1; j=edge[j].next)
{///查找与u相连的最小的层是多少
if(edge[j].flow && MinIndex > Layer[edge[j].v])
{///记录下这条可行弧,下次可以直接访问这条边
MinIndex = Layer[edge[j].v];
cur[u] = j;
}
}
gap[Layer[u]] -= 1;///u改变层,所以u原来所在层的点数减去1
Layer[u] = MinIndex + 1;
gap[Layer[u]] += 1;
if(u != start)
{///返回上一层
u = edge[Stack[--top]].u;
}
}
}
return MaxFlow;
}
int main()
{
int N, M;
while(scanf("%d%d", &N, &M) != EOF)
{
int i, j, u, Ni=pow(2, M), start=Ni+M+1, End=start+1;
char ch;
InIt();
for(i=1; i<=N; i++)
{
u = 0;
for(j=1; j<=M; j++)
{
while(ch = getchar(), ch ==‘ ‘ || ch == ‘\n‘);
u = u*2 + ch-‘0‘;
}
used[u]++;///这种状态的人+1
}
for(i=1; i<Ni; i++)
{
if(used[i])
{
AddEdge(start, i, used[i]);
}
}
for(i=1; i<=M; i++)
{
scanf("%d", &u);
AddEdge(i+Ni, End, u);
}
for(i=1; i<Ni; i++) if(used[i])
{///如果这种状态有人
u = i;
for(j=M; j>0; j--)
{
if(u&1)
{///最后一位是1
AddEdge(i, Ni+j, used[i]);
}
u = u >> 1;
}
}
int MaxFlow = SAP(start, End);
if(MaxFlow == N)
printf("YES\n");
else
printf("NO\n");
}
return 0;
}