http://poj.org/problem?id=3308
题目大意:
地球和火星大战,火星人要摧毁我们的一个武器工厂。已知一个火星人就足以摧毁工厂;
现在我们知道l个火星人将会降落在一个m*n的方阵,而我们的激光枪每次开枪可以杀死一行或者一列的火星人;
但是激光枪架设在不同地方的费用是不一样的;
现在给出激光枪分别架设在m行的第一个位置的费用以及架设n列的第一个位置时的费用,还有l个火星人降落的坐标,求出怎么架设激光枪可以消灭所有火星人并且费用最低;
思路:
先利用二分图的行列匹配建图发构造一个二分图,顶点集VX火星人的横坐标,VY为火星人的纵坐标;在坐标(i,j)上存在火星人就在点i和j之间连一条容量无穷大的边;
构造一个源点s和一个汇点t;
s和VX中每个顶点连一条边,容量为架设在行的对应位置的费用;
VY中的每个顶点和t连一条边,容量为架设在列的对应位置的费用;
求最大流就是问题的解;
#include<iostream>
#include<cstring>
#include<cmath>
#include<queue>
#define min(a,b) a<b?a:b
using namespace std;
const int N=105;
const double MAX=1000000.0;
class Edge
{
public:
int s;
int e;
int next;
double v;
}edge[15*N];
int n;
int edge_num;
int head[N];
int dist[N];
int sp,tp;
void addedge(int u,int v,double c)
{
edge[edge_num].s=u;
edge[edge_num].e=v;
edge[edge_num].v=c;
edge[edge_num].next=head[u];
head[u]=edge_num++;
edge[edge_num].s=v;
edge[edge_num].e=u;
edge[edge_num].v=0.0;
edge[edge_num].next=head[v];
head[v]=edge_num++;
}
bool bfs()
{
queue <int> que;
memset(dist,-1,sizeof(dist));
dist[sp]=0;
que.push(sp);
while(!que.empty())
{
int cur=que.front();
que.pop();
for(int i=head[cur];i!=-1;i=edge[i].next)
{
int u=edge[i].e;
if(dist[u]==-1 && edge[i].v>0)
{
dist[u]=dist[cur]+1;
que.push(u);
}
}
}
return dist[tp]!=-1;
}
double dfs(int a,double b)
{
double flow=0;
if(a==tp)
return b;
for(int i=head[a];i!=-1 && flow<b;i=edge[i].next)
{
int u=edge[i].e;
if(edge[i].v>0 && dist[u]==dist[a]+1)
{
double min_flow=min(edge[i].v,b-flow);
min_flow=dfs(u,min_flow);
flow += min_flow;
edge[i].v -= min_flow;
edge[i^1].v += min_flow;
}
}
if(flow==0)
dist[a]=-2;
return flow;
}
double dinic(int sp,int tp)
{
double max_flow=0.0;
double t;
while(bfs())
{
while(t=dfs(sp,MAX))
max_flow += t;
}
return max_flow;
}
int main(int i)
{
int cases;
double row[N],col[N];
scanf("%d",&cases);
while(cases--)
{
int m,l,a,b;
scanf("%d%d%d",&n,&m,&l);
for(i=1;i<=n;i++)
scanf("%lf",&row[i]);
for(i=1;i<=m;i++)
scanf("%lf",&col[i]);
/*Initial*/
edge_num=0;
memset(head,-1,sizeof(head));
sp=0;
tp=n+m+1;
/*Structure Graph*/
for(i=1;i<=n;i++)
addedge(sp,i,log(row[i]));
for(i=1;i<=m;i++)
addedge(n+i,tp,log(col[i]));
for(i=1;i<=l;i++)
{
scanf("%d%d",&a,&b);
addedge(a,n+b,MAX);
}
double ans=dinic(sp,tp);
printf("%.4lf\n",exp(ans));
}
return 0;
}