poj 3308 Paratroopers(最小割)

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;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值