最近没怎么写博客了, 果断是觉得以前写博客的自己好sb。。。
看到这么丧心病狂的题目背景, 突然就想写写了。。
题意:
有一群丧心病狂的莫名物种的鱼, 每个都认为自己是male( 特么地这样能科学?? ), 然后每条鱼都有一个val值, 并且有可能会攻击它认为是female的鱼, 更加丧心病狂的是攻击了之后会怀孕, 很想问下这是什么攻击。 怀孕之后会产下一个价值为两个父亲的价值XOR的后代, 每条鱼最多只能XX别人一次, 也最多只能被别人XX一次, 然后求产下后代val值的和的最大值。
思路:
将一个点拆成两个点(1~n和n+1~2n), 分别表示XX别人和被别人XX,如果i能XXj 就向i到j+n连一条费用为-val[i]^val[j], 流量为1的边,如果这条边有流量的话就表示iXXj,
源点S = 0, 汇点T = 2 * n + 1, 向S到i连费用为0, 流量为1的边, 向i+n到T连费用为0, 流量1的边。
然后求出最小费用流就可以了。 刚开始以为要满流, wa了几次之后才发现不用满流, 每次找到最短路更新的最小费用的时候顺便更新下答案就可以了。
#include <iostream>
#include <cstdio>
#include <cstring>
#include <queue>
using namespace std;
#define mxn 302
#define mxe 100020
#define inf 0x3f3f3f3f
struct edge {
int u, v, cap, flow, cost, nxt;
edge() {}
edge( int u, int v, int cap, int flow, int cost, int nxt ):
u( u ), v( v ), cap( cap ), flow( flow ), cost( cost ), nxt( nxt ) {}
};
struct mcmf {
edge e[mxe];
int cc, fst[mxn], p[mxn], d[mxn], a[mxn];
bool in[mxn];
void init() {
memset( fst, -1, sizeof( fst ) );
cc = 0;
}
void add( int u, int v, int cap, int cost ) {
e[cc] = edge( u, v, cap, 0, cost, fst[u] );
fst[u] = cc++;
e[cc] = edge( v, u, 0, 0, -cost, fst[v] );
fst[v] = cc++;
}
int bf( int s, int t, int &mf, int &mc ) {
memset( d, 0x3f, sizeof( d ) );
memset( in, 0, sizeof( in ) );
d[s] = 0, a[s] = inf, in[s] = 1, p[s] = 0;
queue<int> q;
q.push( s );
while( !q.empty() ) {
int x = q.front(); q.pop();
in[x] = 0;
for( int i = fst[x]; ~i; i = e[i].nxt ) {
int v = e[i].v;
if( e[i].cap > e[i].flow && d[v] > d[x] + e[i].cost ) {
d[v] = d[x] + e[i].cost;
p[v] = i;
a[v] = min( a[x], e[i].cap - e[i].flow );
if( !in[v] )
in[v] = 1, q.push( v );
}
}
}
if( d[t] == inf )
return 0;
mf += a[t];
mc += a[t] * d[t];
int u = t;
while( u != s ) {
e[p[u]].flow += a[t];
e[p[u]^1].flow -= a[t];
u = e[p[u]].u;
}
return 1;
}
int go( int s, int t ) {
int res = 0;
int mf = 0, mc = 0;
while( bf( s, t, mf, mc ) ) {
res = min( res, mc );
}
return res;
}
}go;
int n, a[mxn], S, T;
char s[mxn];
int main() {
while( scanf( "%d", &n ) != EOF && n ) {
S = 0, T = 2 * n + 1;
for( int i = 1; i <= n; ++i )
scanf( "%d", &a[i] );
go.init();
for( int i = 1; i <= n; ++i ) {
scanf( "%s", s + 1 );
for( int j = 1; j <= n; ++j )
if( s[j] == '1' )
go.add( i, j + n, 1, - ( a[i] ^ a[j] ) );
go.add( S, i, 1, 0 );
go.add( i + n, T, 1, 0 );
}
printf( "%d\n", - go.go( S, T ) );
}
return 0;
}