POJ 3308 Paratroopers

题目链接:http://poj.org/problem?id=3308

解析:抽象成二分图,左边的点是行,右边的点是列,如果行列之间有入侵者的话,就用边容量为Max的边连接行列点在加入源点(源点连接所有的行点)和汇点(汇点连接所有的列点)。(好吧,╮(╯▽╰)╭,为什么这么建图我也不是太明了,就知道这么建的话可以把问题转换成求最大流问题)

如果源点到汇点之间有通路的话,必然行点集和列点集之间有至少一条路,反应到矩阵中,就是至少有一个机器人没被杀死。所以要使所有机器人都被杀,就得使s,t之间不能有通路,因为要求消耗最小,所以是最小割

所以我们需要求该图的最小割,即是求最大流,然后用EK算法求出来的全是和,题目要求求积,那么存边权的时候就存ln(边权),ln(a)+ln(b) = ln(a*b),最后的话,a*b=e(lna+lnb)

#include<stdio.h>
#include<string.h>
#include<math.h>
#include<queue>
#define min(x,y) x<y?x:y
#define Max 100000000
using namespace std;

double cap[110][110],flow[110];
int m,n,l;
double ans;
int pre[110];
double bfs(int start,int end)
{
	queue<int>Q;
	while(!Q.empty())
		Q.pop();
	memset(pre,-1,sizeof(pre));
	memset(flow,0,sizeof(flow));
	pre[start] = 0;
	flow[start] = Max;
	Q.push(start);
	while(!Q.empty())
	{
		int temp = Q.front();
		Q.pop();
		if(temp == end)
			break;
		for(int i = 0 ; i <= m+n+1;i++)
		{
			if(cap[temp][i] > 0 && pre[i] == -1)
			{
				flow[i] = min(flow[temp],cap[temp][i]);
				pre[i] = temp;
				Q.push(i);
			}
		}
	}
	
	return flow[end];
}

void EK(int start ,int end)
{
	while(1)
	{
		double t = bfs(start,end);
		if(t == 0)
			break;
		for(int k = end; k!= start; k = pre[k])
		{
			cap[pre[k]][k] -= t;
			cap[k][pre[k]] += t;
		}
		ans += t;
	}	
}

int main()
{
	int T;
	scanf("%d",&T);
	while(T--)
	{
		memset(cap,0,sizeof(cap));
		scanf("%d%d%d",&m,&n,&l);
		for(int i = 1 ; i  <= m ; i ++)	//1->m是行点,也是二分图的左边点集,全都连到源点0上
		{
			double a;
			scanf("%lf",&a);
			cap[0][i] = log(a);
		}
		for(int i = 1; i <= n ; i ++) //m+1->m+n是列点,也是二分图的右点集,连接到汇点m+n+1上
		{
			double a;
			scanf("%lf",&a);
			cap[m+i][m+n+1] = log(a);
		}
		for(int i = 1; i <= l ; i ++)
		{
			int a,b;
			scanf("%d%d",&a,&b);
			cap[a][m+b] = Max;
		}
		ans = 0;
		EK(0,m+n+1);
		printf("%.4lf\n",exp(ans));
	}
	return 0;
}


 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值