//简单KM,,要注意的是XOR是异或的意思。。不要看不懂。。我看了半天才知道。。
//这个知道了就可以很简单的KM了。。这个题目也可以用最小费用最大流来做。。但是图比较难建。。
#include <iostream>
#include <stdio.h>
#define MAX 105
#define min(a,b) a<b?a:b
#define max(a,b) a>b?a:b
int lx[MAX],ly[MAX],match[MAX],visx[MAX],visy[MAX],lack,g;
int map[MAX][MAX];
using namespace std;
int dfs(int x)
{//匈牙利
visx[x]=1;
for(int i=0;i<g;i++){
if(!visy[i] && lx[x]+ly[i]==map[x][i])
{
visy[i]=1;
if(match[i]==-1 || dfs(match[i]))
{
match[i]=x;
return 1;
}
}
}
return 0;
}
int KM()
{
int i,j,k;
for(i=0;i<g;i++)
{//初始化顶标
lx[i]=INT_MIN; ly[i]=0;
for(j=0;j<g;j++)
lx[i]=max(map[i][j],lx[i]);
}
memset(match,-1,sizeof(match));
for(i=0;i<g;i++)
{
while(1){//直到每个点都成功匹配,才结束循环
memset(visx,0,sizeof(visx));
memset(visy,0,sizeof(visy));
if(dfs(i))break; //如果点 i 成功匹配,则不需要调整定标值
/*------------顶标调整------------*/
int lack=INT_MAX;//顶标调整值
for(j=0;j<g;j++)
{
if(visx[j])
{
for(k=0;k<g;k++)
{//取幅度最小的值为调整值
if(!visy[k])lack=min(lx[j]+ly[k]-map[j][k],lack);
}
}
}
for(j=0;j<g;j++){//调整已经得到匹配的点对的顶标值
if(visx[j])lx[j]-=lack;
if(visy[j])ly[j]+=lack;
}
/*---------------------------------*/
}
}
int sum=0;
for(i=0;i<g;i++)
{
if(match[i]!=-1)
sum+=map[match[i]][i];
}
return sum;
}
int main()
{
int n,i,j;
char ch;
int value[MAX];
while(cin>>n)
{
memset(map,0,sizeof(map));
if(n==0)break;
for(i=0;i<n;i++)
cin>>value[i];
for(i=0;i<n;i++)
for(j=0;j<n;j++)
{
cin>>ch;
if(ch=='1')
{
//cout<<value[i]<<" "<<value[j]<<endl;
map[i][j]=value[i]^value[j];
// cout<<map[i][j]<<endl;
//cout<<" **********"<<endl;
}
}
/* for(i=0;i<n;i++)
{
//cout<<endl;
for(j=0;j<n;j++)
cout<<map[i][j]<<" ";
}*/
g=n;
int res=KM();
cout<<res<<endl;
}
return 0;
}