poj 3308 最小割

应用到:最小割等于最大流定理

技巧:割边的乘积最小,用log转化!!太好了!!

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <algorithm>
#include <vector>
#include <cmath>
using namespace std;
int m,n,l,s,t;
#define N 120
#define M 2000
const double INF =1000000000000.0;
#define eps 1e-12
bool equal(double a,double b)
{
	return fabs(a-b)<eps;
}
struct Edge
{
	int v;
	double w;
}edge[M];
int adj[M],head[N],e;

int q[N*2],front,rear,vis[N],gap[N],arc[N],dist[N],pre[N];
double sap(int s,int t)
{
	memset(vis,0,sizeof(vis));
	memset(gap,0,sizeof(gap));
	memset(pre,-1,sizeof(pre));
	memset(arc,-1,sizeof(arc));
	front=rear=0;
	q[rear++]=t;dist[t]=0;gap[0]++;vis[t]=1;
	while(front<rear)
	{
		int u=q[front++];
		for(int i=head[u];i!=-1;i=adj[i])
			if(!vis[edge[i].v])
			{
				q[rear++]=edge[i].v;
				vis[edge[i].v]=1;
				arc[edge[i].v]=head[edge[i].v];
				dist[edge[i].v]=dist[u]+1;
				gap[dist[edge[i].v]]++;
			}
	}
	double ans=0.0;
	int u=s;double low=INF-1;pre[s]=s;
	while(dist[s]<m+n+2)
	{
		bool flag=false;
		for(int &i=arc[u];i!=-1;i=adj[i])
			if(!equal(edge[i].w,0.0) && dist[u]==dist[edge[i].v]+1)
			{
				flag=true;
				low=min(low,edge[i].w);
				pre[edge[i].v]=u;
				u=edge[i].v;
				if(u==t)
				{
					while(u!=s)
					{
						u=pre[u];
						edge[arc[u]].w-=low;
						edge[arc[u]^1].w+=low;
					}
					ans+=low;
					low=INF-1;
				}
				break;
			}
		if(flag)
			continue;

		int mindist=m+n+2;
		for(int i=head[u];i!=-1;i=adj[i])
			if(!equal(edge[i].w,0.0) && mindist>dist[edge[i].v])
			{
				arc[u]=i;
				mindist=dist[edge[i].v];
			}
		gap[dist[u]]--;
		if(gap[dist[u]]==0)
			break;
		dist[u]=mindist+1;
		gap[dist[u]]++;
		u=pre[u];
	}
	return ans;
}
void addedge(int u,int v,double w)
{
	edge[e].v=v;edge[e].w=w;adj[e]=head[u];head[u]=e++;
	edge[e].v=u;edge[e].w=0;adj[e]=head[v];head[v]=e++;
}
void init()
{
	e=0;s=0;t=m+n+1;
	memset(head,-1,sizeof(head));
}
int main ()
{
	int test;scanf("%d",&test);
	while(test--)
	{
		scanf("%d%d%d",&m,&n,&l);
		init();
		double temp;
		for(int i=1;i<=m;++i)
		{
			scanf("%lf",&temp);
			addedge(s,i,log(temp));
		}
		for(int i=m+1;i<=m+n;++i)
		{
			scanf("%lf",&temp);
			addedge(i,t,log(temp));
		}
		int u,v;
		while(l--)
		{
			scanf("%d%d",&u,&v);
			addedge(u,m+v,INF);
		}

		double ans=sap(s,t);
		ans=exp(ans);
		printf("%.4lf\n",ans);
	}
	return 0;
}



你可能感兴趣的:(poj 3308 最小割)