POJ 3308 Paratroopers【最大流】
2012-08-23 23:35
281 查看
题意: 一群伞兵要降落在一个m*n的区域,知道了每个伞兵落入的位置,防守方可以在任意一排或任意一列安装武器,分别可以防御某一排或某一列的敌人,知道了武器放
某一排或某一列的建造费用,找出一种建造方案使得所有武器花费的乘以最小并足以防御任意一个位置的敌人。
分析:建图方式:
将每一行看成一个点(1..n),将每一列看成一个点(n..n+m)
建立一个源点 s = 0, 汇点 t = n+m+1
在 s 和每个行顶点之间连一条容量为行造价的边
在每个列顶点和 t 之间连一条容量为列造价的边
如果(x,y)位置有伞兵,就在 x 行和y列之间连一条容量为无穷大的边
求出最小割即为最小费用,需要注意的地方是要通过取对数的方式将乘积转化为和。
某一排或某一列的建造费用,找出一种建造方案使得所有武器花费的乘以最小并足以防御任意一个位置的敌人。
分析:建图方式:
将每一行看成一个点(1..n),将每一列看成一个点(n..n+m)
建立一个源点 s = 0, 汇点 t = n+m+1
在 s 和每个行顶点之间连一条容量为行造价的边
在每个列顶点和 t 之间连一条容量为列造价的边
如果(x,y)位置有伞兵,就在 x 行和y列之间连一条容量为无穷大的边
求出最小割即为最小费用,需要注意的地方是要通过取对数的方式将乘积转化为和。
#include<stdio.h> #include<string.h> #include<math.h> #define clr(x)memset(x,0,sizeof(x)) #define maxn 105 const double INF=999999999.0; double c[maxn][maxn]; int gap[maxn]; // 用 gap 记录当前标号为 i 的个数, int dis[maxn]; // 用于 gap 优化 void init(int s,int t,int n) // 初始化 dis 数组,将图分层 { int v,x,q[maxn],front=0,rear=0; memset(gap,0,sizeof(gap)); memset(dis,0xff,sizeof(dis)); q[rear++]=t; dis[t]=0; while(front<rear) { x=q[front++]; gap[dis[x]]++; for(v=0;v<n;v++) // 从下标的最小值到最大值 { if(dis[v]==-1&&c[v][x]>0) { dis[v]=dis[x]+1; q[rear++]=v; } } } } double sap_flow(int s,int t,int n) { init(s,t,n); int top=s,i,j,k; // top 是当前增广路中最前面的一个点 int pre[maxn]; double low[maxn]; double flow=0; memset(low,0,sizeof(low)); while(dis[s]<n) // 小于总节点数 { int flag=0; low[s]=INF; for(i=0;i<n;i++) // 从下标的最小值最大值,有时候最后一个可能是n-1 !! if(c[top][i]>0&&dis[top]==dis[i]+1&&dis[i]>=0) // 找允许弧 { flag=1; break; } if(flag) // 找到允许弧 { low[i]=c[top][i]; if(low[i]>low[top]) low[i]=low[top]; // 更新 low 值 pre[i]=top; top=i; if(top==t) // 找到一条增广路 { flow+=low[t]; j=top; while(j!=s) // 更新残留网络 { k=pre[j]; c[k][j]-=low[t]; c[j][k]+=low[t]; j=k; } top=s; // 再从头找 memset(low,0,sizeof(low)); } } else // 如果没有找到允许弧 { int min=n-1; for(j=0;j<n;j++) // 从下标的最小值最大值,有时候最后一个可能是n-1 !! { // 昭和 top 相邻 dis 最小的点 if(c[top][j]>0&&dis[j]+1<min&&dis[j]>=0) min=dis[j]+1; } gap[dis[top]]--; if(gap[dis[top]]==0) break; gap[min]++; dis[top]=min; // 更新 top 距离值 if(top!=s) // 回溯找其他的路径 top=pre[top]; } } return flow; } int main() { int s,t,T,i,n,m,p,a,b; double w; scanf("%d",&T); while(T--) { scanf("%d%d%d",&n,&m,&p); s=0; t=n+m+1; clr(c); for(i=1;i<=n;i++) { scanf("%lf",&w); c[s][i]=log(w); } for(i=1;i<=m;i++) { scanf("%lf",&w); c[i+n][t]=log(w); } for(i=1;i<=p;i++) { scanf("%d%d",&a,&b); c[a][b+n]=INF; } printf("%.4lf\n",exp(sap_flow(s,t,n+m+2))); } return 0; }
相关文章推荐
- poj 3308 Paratroopers 最小割—最大流
- POJ 3308 Paratroopers 最小割、最大流
- POJ 3308 Paratroopers(最大流最小割の最小点权覆盖)
- [POJ 3308]Paratroopers[最大流]
- POJ 3308 Paratroopers 最大流,乘积化和 难度:2
- POJ---3308-Paratroopers(最大流)
- POJ - 3308 Paratroopers(最大流)
- (模板题)poj 3308 Paratroopers(Dinic算法最大流)
- POJ3308_Paratroopers(最大流最小割)
- POJ 3308 Paratroopers
- 【最小割】POJ-3308 Paratroopers
- poj 3308 Paratroopers 最小割 最小点权覆盖
- poj3308 Paratroopers --- 最小点权覆盖->最小割
- 【POJ】3308 Paratroopers 化乘为加——最小点权覆盖
- POJ 3308 Paratroopers
- POJ 3308 Paratroopers(最小割EK)
- POJ 3308 Paratroopers(最小割+Dinic)
- POJ 3308 Paratroopers
- POJ 3308 Paratroopers 最小点权覆盖Dinic
- poj 3308 zoj 2874 Paratroopers(最小割)