POJ 3308 Paratroopers
来源:互联网 发布:手机文件传输软件 编辑:程序博客网 时间:2024/05/16 06:27
题目大意:
在一个n*m的格子地图上有l个外星人,有一种激光炮可以消灭他们,每当使用一次可以使某一行或某一列的外星人消失。但每使用一次都需要付一定的价钱。给出在每一行或每一列使用激光炮时需要的价格,问最少需要付多少才能消灭全部外星人。总价格是每一次使用价格的乘积。
解题思路:
这题看起来跟POJ3041差不多,但在这里增加了价格就不一样了。虽然建出来的图类似于一个二分图,但是在这里得用求最小割的办法来解决问题,也就建图的时候需要一个超级源点和超级汇点。
1、首先建图,超级汇点向坐标X依次建边,前向边的容量是在下表是X的那一行使用激光炮的价格取log(),(注1)后向边容量为零。同理建出向坐标Y到超级汇点的。
2、对于每一个外星人的坐标,建立相应X点到Y点的边,前向边容量无穷大,后向边容量为0。
3、然后使用Dinic算法求出最大流,也就是最小割容量。
4、用exp() 求出最小花费,
注意:
1、因为求最大流或者最小割是一个求和的过程,如果最小花费是乘积需要对数转化。
2、注意double的精度问题。
下面是代码:
#include <stdio.h>#include <string.h>#include <queue>#include <math.h>using namespace std;const int inf=1e8;const int Maxn=1005;const double eps = 0.00000001;struct node{ int v,next; double w;} edge[ Maxn*5];int n,m,l,head[Maxn],cnt,deep[Maxn];void init(){ memset(head,-1,sizeof(head)); cnt=0;}double Eps(double x){ return fabs(x)<eps?0:x;}double min(double a,double b){ return a<b?a:b;}void addedge(int u,int v,double w){ edge[cnt].v=v; edge[cnt].w=w; edge[cnt].next=head[u]; head[u]=cnt; cnt++; edge[cnt].v=u; edge[cnt].w=0; edge[cnt].next=head[v]; head[v]=cnt; cnt++;}bool bfs(){ memset(deep,-1,sizeof(deep)); queue <int > q; q.push(0); deep[0]=0; while(!q.empty()) { int t=q.front(); q.pop(); int p=head[t]; while(p!=-1) { int v=edge[p].v; if( deep[v]==-1&&Eps(edge[p].w)>0) { q.push(v); deep[v]=deep[t]+1; } p=edge[p].next; } } return deep[n+m+1]!=-1;}void does(int u,int v,double w){ int p =head[u]; while(edge[p].v!=v) { p=edge[p].next; } edge[p].w+=w;}double dfs(int src,double flow){ if(src==n+m+1)return flow; double sum=0; int p=head[src]; while(p!=-1) { int v=edge[p].v; if(deep[v]==deep[src]+1&&Eps(edge[p].w)>0) { double tmp=dfs(v,min(flow-sum,edge[p].w)); sum+=tmp; edge[p].w-=tmp; does(v,src,tmp); } p=edge[p].next; } return sum;}double dinic(){ double ans=0; while(bfs()) { ans+=dfs(0,inf); } return ans;}int main(){ int T; scanf("%d",&T); while(T--) { double val; int u,v; init(); scanf("%d%d%d",&n,&m,&l); for(int i=1; i<=n; i++) { scanf("%lf",&val); addedge(0,i,log(val)); } for(int i=1; i<=m; i++) { scanf("%lf",&val); addedge(n+i,n+m+1,log(val)); } for(int i=0; i<l; i++) { scanf("%d%d",&u,&v); addedge(u,v+n,inf); } printf("%0.4f\n",exp(dinic())); } return 0;}
0 0
- POJ 3308 Paratroopers
- poj 3308 Paratroopers
- poj 3308 Paratroopers
- POJ 3308 Paratroopers
- POJ 3308: Paratroopers
- POJ 3308 Paratroopers
- POJ 3308 Paratroopers
- POJ-3308-Paratroopers
- poj 3308 Paratroopers
- poj 3308 Paratroopers
- POJ 3308 Paratroopers
- poj 3308 Paratroopers
- POJ 3308--Paratroopers
- POJ 3308 Paratroopers //最小割
- poj 3308 Paratroopers 网络流
- 【最小割】POJ-3308 Paratroopers
- (最小割)poj 3308 Paratroopers
- [POJ 3308]Paratroopers[最大流]
- 学习Linux
- 让vim编辑器始终有行号
- 使用Unity3D开发项目的一点经验
- KVM和远程管理工具virt-manager的部署
- 【转载】java 内存配置
- POJ 3308 Paratroopers
- Java design pattern 设计模式
- java 继承详解
- windows下git安装
- ClientDataSet中Cancel与CancelUpdates的区别
- Python学习系列十一:动态类型
- 使用fread和fwrite函数读写文件
- [Stirling] HDU 3625 Examining the Rooms
- codeforces/problem/175/C 贪心