碰到一道非常讨厌的网络流。
因为精度的问题,
多路增广的dinic会WA。
只好仿照SPFA增广求费用流的写法来写了一个感觉像单路增广dinic的东西
题目链接:http://poj.org/problem?id=3308
题意:
一个n*m的网格上有一些点。
消去某一行上的点有一个代价,
消去某一列上的点也有一个代价,
这些代价都是实数且不小于1.0。
所需的总代价是这些代价的乘积。
问消去所有点需花费的最小代价。
算法 :
很经典的最小割模型。
取对数化乘为加。
代码如下:
#include<cstdio>
#include<iostream>
#include<sstream>
#include<cstdlib>
#include<cstring>
#include<string>
#include<climits>
#include<cmath>
#include<algorithm>
#include<queue>
#include<vector>
#include<stack>
#include<set>
#include<map>
#define INF 0x3f3f3f3f
#define eps 1e-8
using namespace std;
const int MAXN=200;
const int MAXM=100000;
int head[MAXN],Q[MAXN],p[MAXN];
bool vis[MAXN];
int to[MAXM],nxt[MAXM];
double cap[MAXM];
int E;
void _addedge(int u, int v, double w) {
nxt[E]=head[u];
to[E]=v;
cap[E]=w;
head[u]=E++;
}
void addedge(int u, int v, double w) {
_addedge(u,v,w);
_addedge(v,u,0.0);
}
bool bfs(int S, int T, int n) {
memset(vis,0,sizeof(vis));
vis[T]=true;
int front=0,rear=0;
Q[rear++]=T;
while(front!=rear&&!vis[S]) {
int u=Q[front++];
for(int i=head[u]; i!=-1; i=nxt[i]) {
if(cap[i^1]<eps) {
continue;
}
int v=to[i];
if(!vis[v]) {
p[v]=i;
vis[v]=true;
Q[rear++]=v;
}
}
}
return vis[S];
}
double dfs(int S, int T, int n, double lim) {
double tmp=INT_MAX;
for(int u=S; u!=T; u=to[p[u]^1]) {
tmp=min(tmp,cap[p[u]^1]);
if(tmp<eps) {
return 0.0;
}
}
for(int u=S; u!=T; u=to[p[u]^1]) {
cap[p[u]^1]-=tmp;
cap[p[u]]+=tmp;
}
return tmp;
}
double dinic(int S, int T, int n) {
double ans=0.0;
while(bfs(S,T,n)) {
ans+=dfs(S,T,n,INT_MAX);
}
return ans;
}
int main() {
int cas;
scanf("%d",&cas);
while(cas--) {
int n,m,k;
scanf("%d%d%d",&n,&m,&k);
int S=0,T=n+m+1;
memset(head,-1,sizeof(head));
E=0;
for(int i=0; i<n; i++) {
double cap;
scanf("%lf",&cap);
addedge(S,i+1,log(cap));
}
for(int i=0; i<m; i++) {
double cap;
scanf("%lf",&cap);
addedge(i+n+1,T,log(cap));
}
while(k--) {
int x,y;
scanf("%d%d",&x,&y);
x--;
y--;
addedge(x+1,y+n+1,INT_MAX);
}
printf("%.4f\n",exp(dinic(S,T,n+m+2)));
}
return 0;
}