题意:给定二分图,求权值最大的匹配,
思路:1.KM,因为题目给定的图不是完全图,可能没有完全匹配,所以要加上虚拟的权值为0的边,
所有情况,包括权值最大的情况也是属于某一完全匹配的,所以可以直接求KM,
2.费用流:不加虚拟边,求得的是在最大流情况下的权值最大,
加上虚拟边后,所有情况,包括最大权值情况都是属于某一最大流,所以直接求费用流
费用流:
#include<cstdio>
#include<iostream>
#include<cstring>
#include<queue>
#include<cmath>
using namespace std;
const int N=200+10;
const int M=200000+10;
const int INF=1<<30;
inline int min(int a,int b)
{
return a<b?a:b;
}
struct Edge
{
int from,to,next,cap,cost;
}e[M];
int head[N];
int in()
{
int res = 0 , ch ;
while( !( ( ch = getchar() ) >= '0' && ch <= '9' ) );
res = ch - '0' ;
while( ( ch = getchar() ) >= '0' && ch <= '9' )
res = res * 10 + ( ch - '0' ) ;
return res ;
}
struct Mcmf
{
int total;
int dis[N],vis[N];
int path[N],low[N];
void init()
{
total=0;
memset(head,-1,sizeof(head));
}
void add_edges(int from,int to,int cap,int cost)
{
e[total].from=from;
e[total].cap=cap;
e[total].to=to;
e[total].cost=cost;
e[total].next=head[from];
head[from]=total++;
e[total].from=to;
e[total].cap=0;
e[total].to=from;
e[total].cost=-cost;
e[total].next=head[to];
head[to]=total++;
}
int Spfa(int s,int t)
{
memset(vis,0,sizeof(vis));
memset(path,-1,sizeof(path));
memset(dis,0x6f,sizeof(dis));
queue<int > qq;
qq.push(s);
vis[s]=1;
dis[s]=0;
while(!qq.empty())
{
//printf("ans\n");
int u=qq.front();qq.pop();
vis[u]=0;
for(int i=head[u];i!=-1;i=e[i].next)
{
int v=e[i].to;
if(e[i].cap>0&&(dis[v]>dis[u]+e[i].cost))
{
path[v]=i;
dis[v]=dis[u]+e[i].cost;
if(!vis[v])
{
vis[v]=1;
qq.push(v);
}
}
}
}///while
if(path[t]==-1)return 0;
return 1;
}
int _mcmf(int s,int t)
{
int flow=0;
int cost=0;
while(Spfa(s,t))
{
int f=INF;
for(int i=t;i!=s;i=e[path[i]].from)
{
//printf("%d-",i);
f=min(f,e[path[i]].cap);
}
//printf("\n");
for(int i=t;i!=s;i=e[path[i]].from)
{
e[path[i]].cap-=f;
e[path[i]^1].cap+=f;
}
flow+=f;
cost+=dis[t];
}
//printf("flow=%d\n",flow);
return cost;
}
}mcmf;
int aa[150];
char str[150];
int main()
{
int n;
while(scanf("%d",&n),n)
{
mcmf.init();
for(int i=1;i<=n;i++)
{
scanf("%d",&aa[i]);
mcmf.add_edges(0,i,1,0);
mcmf.add_edges(i+n,2*n+1,1,0);
}
for(int i=1;i<=n;i++)
{
scanf("%s",str);
for(int j=0;j<n;j++)
{
if(str[j]=='1')
{
mcmf.add_edges(i,j+1+n,1,-(aa[i]^aa[j+1]));
//printf("%d,",aa[i]^aa[j+1]);
}
else mcmf.add_edges(i,j+1+n,1,0);
}
//printf("\n");
}
int ans=mcmf._mcmf(0,2*n+1);
printf("%d\n",-ans);
}
return 0;
}