Special Fish
Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 1214 Accepted Submission(s): 462
A fish will spawn after it has been attacked. Each fish can attack one other fish and can only be attacked once. No matter a fish is attacked or not, it can still try to attack another fish which is believed to be female by it.
There is a value we assigned to each fish and the spawns that two fish spawned also have a value which can be calculated by XOR operator through the value of its parents.
We want to know the maximum possibility of the sum of the spawns.
The last test case is followed by a zero, which means the end of the input.
3 1 2 3 011 101 110 0
6
题意:有n条鱼,每条鱼都认为自己是公的,如果鱼a认为鱼b是母的,那么a就会攻击b ; 之后就会交配产卵; 每条鱼最多能被攻击一次和攻击别的鱼一次;
每条鱼有一个价值a[i],当 i 攻击 j ,就会得到一个价值为 a[i]^a[j] ;求怎样交配使得总价值最大 ;
1表示认为别人是母的,0表示认为是公的 ;
有两种做法 :
(1)最大权匹配 : 当a认为是b母是的时候,也就是鱼a可以攻击b,当然也可以不攻击,看你怎么分配 ; a->b连边 ; 权值为a[i]^a[j] ;
然后就是求一个最大权匹配;注意不一定是完全匹配,因为可能匹配的边很少(认为是母的很少) ;
#include<cstdio>
#include<cstring>
#include<map>
#include<vector>
#include<cmath>
#include<cstdlib>
#include<stack>
#include<queue>
#include <iomanip>
#include<iostream>
#include<algorithm>
using namespace std ;
const int N=200 ;
const int inf=1<<30 ;
int w[N][N] ,lx[N],ly[N],fx[N],fy[N],match[N] ;
int n ;
int dfs(int u)
{
fx[u]=1;
for(int i = 1 ; i <= n ; i++)
{
if(!fy[i] && lx[u]+ly[i]==w[u][i])
{
fy[i]=1;
if(match[i]==-1 || dfs(match[i]))
{
match[i]=u;
return 1;
}
}
}
return 0;
}
int KM()
{
memset(ly,0,sizeof(ly));
memset(match,-1,sizeof(match));
for(int i = 1 ; i<= n ; i++)
{
lx[i]=-1;
for(int j = 1 ; j <= n ; j++)
lx[i] = max(lx[i],w[i][j]);
}
for(int k = 1 ; k <= n ; k++)
{
while(1)
{
memset(fx,0,sizeof(fx));
memset(fy,0,sizeof(fy));
if(dfs(k)) break;
int d=inf ;
for(int i = 1 ; i <= n ; i++)
if(fx[i])
for(int j = 1 ; j <= n ; j++)
if(!fy[j])
d=min(d,lx[i]+ly[j]-w[i][j]);
for(int i = 1 ; i <= n ; i++)
{
if(fx[i]) lx[i] -= d ;
if(fy[i]) ly[i] += d ;
}
}
}
int ans=0;
for(int i = 1 ; i <= n ; i++)
ans += w[match[i]][i];
return ans ;
}
int main()
{
char ch;
int a[200];
while(~scanf("%d",&n))
{
if(n==0) break ;
memset(w,0,sizeof(w));
for(int i = 1 ; i<= n ; i++ )
scanf("%d",&a[i]);
for(int i = 1 ; i <= n ; i++)
for(int j = 1 ; j <= n ; j++)
{
cin>>ch ;
if(ch=='1')
{
w[i][j] = a[i]^a[j] ;
}
}
printf("%d\n",KM());
}
return 0;
}
最小费用最大流 :
拆点 i , i+n ;
因为每条鱼最多 被攻击和主动攻击一次; 所以源点连 每条鱼 i ; 表示每条鱼被攻击一次 ,流量1,费用0;
add(s,i,1,0);
之后,i+n 连汇点t ,表示主动攻击一次 ; 流量1,费用0 ,add(i+n,t,1,0)
然后,当 a->b ; add(a,b+n,1, -(a[i]^a[j]) ) ;注意,要求最大价值,所以把权值 边负数就好了 ;
然后没条鱼可以选择不去攻击别的鱼,所以没条鱼 i 连汇点t,相当于绕过 i+n,不走这条边 i+n->t ;通过i+n->t 的都是两条鱼攻击了的 ;
#include<cstdio>
#include<cstring>
#include<map>
#include<vector>
#include<cmath>
#include<cstdlib>
#include<stack>
#include<queue>
#include <iomanip>
#include<iostream>
#include<algorithm>
using namespace std ;
const int N=200 ;
const int M=N*N ;
const int inf=1<<30 ;
struct node
{
int u,v,c,cost,next;
}edge[M];
int pp[N],pre[N],head[N],vist[N],dist[N];
int top ;
void add(int u ,int v,int c,int cost)
{
edge[top].u=u;
edge[top].v=v;
edge[top].c=c;
edge[top].cost=cost;
edge[top].next=head[u];
head[u]=top++;
edge[top].u=v;
edge[top].v=u;
edge[top].c=0;
edge[top].cost=-cost;
edge[top].next=head[v];
head[v]=top++;
}
int SPFA(int s,int t)
{
int u , v ;
memset(vist,0,sizeof(vist));
memset(pre,-1,sizeof(pre));
for(int i = 0 ; i <= t ; i++) dist[i]=inf ;
vist[s]=1;dist[s]=0;pre[s]=s;
queue<int>q;
q.push(s);
while(!q.empty())
{
u=q.front();
q.pop();
vist[u]=0;
for(int i =head[u];i!=-1;i=edge[i].next)
{
v=edge[i].v;
if(edge[i].c && dist[v] > dist[u]+edge[i].cost)
{
dist[v] = dist[u]+edge[i].cost ;
pre[v]=u;
pp[v]=i;
if(!vist[v]);
{
vist[v]=1;
q.push(v);
}
}
}
}
if(dist[t]==inf) return 0;
return 1 ;
}
int MFMC(int s,int t)
{
int mincost=0,flow=0,minflow ;
while(SPFA(s,t))
{
minflow=inf;
for(int i=t;i!=s;i=pre[i])
minflow=min(minflow,edge[pp[i]].c);
for(int i=t;i!=s;i=pre[i])
{
edge[pp[i]].c -= minflow;
edge[pp[i]^1].c += minflow;
}
flow += minflow;
mincost += dist[t]*minflow ;
}
return -mincost ;
}
int main()
{
int n;
int a[200];
char ch ;
while(~scanf("%d",&n))
{
if(n==0) break;
top=0;
memset(head,-1,sizeof(head));
int s=0,t=2*n+1 ;
for(int i = 1 ; i <= n; i++)
scanf("%d",&a[i]);
for(int i = 1 ; i <= n ; i++)
{
add(s,i,1,0);
add(i,t,1,0);
add(i+n,t,1,0);
for(int j = 1 ; j <= n ; j++)
{
cin>>ch ;
if(ch=='1')
{
add(i,j+n,1,-(a[i]^a[j])) ;
}
}
}
int ans=MFMC(s,t);
printf("%d\n",ans);
}
return 0;
}