【刷题】洛谷 P4329 [COCI2006-2007#1] Bond

题意翻译

\(n\) 个人去执行 \(n\) 个任务,每个人执行每个任务有不同的成功率,每个人只能执行一个任务,求所有任务都执行的总的成功率。

输入第一行,一个整数 \(n\)\(1\leq n\leq 20\) ),表示人数兼任务数。接下来 \(n\) 行每行 \(n\) 个数,第 \(i\) 行第 \(j\) 个数表示第 \(i\) 个人去执行第 \(j\) 个任务的成功率(这是一个百分数,在 \(0\)\(100\) 间)。

输出最大的总成功率(这应也是一个百分数)

题目描述

Everyone knows of the secret agent double-oh-seven, the popular Bond (James Bond). A lesser known fact is that he actually did not perform most of his missions by himself; they were instead done by his cousins, Jimmy Bonds. Bond (James Bond) has grown weary of having to distribute assign missions to Jimmy Bonds every time he gets new missions so he has asked you to help him out. Every month Bond (James Bond) receives a list of missions. Using his detailed intelligence from past missions, for every mission and for every Jimmy Bond he calculates the probability of that particular mission being successfully completed by that particular Jimmy Bond. Your program should process that data and find the arrangement that will result in the greatest probability that all missions are completed successfully. Note: the probability of all missions being completed successfully is equal to the product of the probabilities of the single missions being completed successfully.

输入输出格式

输入格式:

The first line will contain an integer N, the number of Jimmy Bonds and missions (1 ≤ N ≤ 20). The following N lines will contain N integers between 0 and 100, inclusive. The j-th integer on the ith line is the probability that Jimmy Bond i would successfully complete mission j, given as a percentage.

输出格式:

Output the maximum probability of Jimmy Bonds successfully completing all the missions, as a percentage.

输入输出样例

输入样例#1:

2
100 100
50 50

输出样例#1:

50.000000

输入样例#2:

2
0 50
50 0

输出样例#2:

25.00000

输入样例#3:

3
25 60 100
13 0 50
12 70 90

输出样例#3:

9.10000

说明

Clarification of the third example: If Jimmy bond 1 is assigned the 3rd mission, Jimmy Bond 2 the 1st mission and Jimmy Bond 3 the 2nd mission the probability is: 1.0 0.13 0.7 = 0.091 = 9.1%. All other arrangements give a smaller probability of success. Note: Outputs within ±0.000001 of the official solution will be accepted.

题解

考虑建出二分图
发现这题很想带权二分图匹配是吧,但是由于答案是算乘法,所以不能直接匹配
思考乘法的转化 \(a=x^{log_xa}\)\(a*b=x^{log_xa}x^{log_xb}=x^{log_xa+log_xb}\)
于是就很好地把乘法变成了加法
于是就可以上费用流跑带权二分图匹配了
注意,0没有对数,所以要特判

#include<bits/stdc++.h>
#define ui unsigned int
#define ll long long
#define db double
#define ld long double
#define ull unsigned long long
const int MAXN=20+5,intinf=0x3f3f3f3f;
const db doubleinf=1000000000.00;
int n,e=1,to[MAXN*MAXN*2],nex[MAXN*MAXN*2],beg[MAXN<<1],cap[MAXN*MAXN*2],p[MAXN<<1],cur[MAXN<<1],vis[MAXN<<1],clk,s,t;
db was[MAXN*MAXN*2],ans,level[MAXN<<1];
std::queue<int> q;
template<typename T> inline void read(T &x)
{
	T data=0,w=1;
	char ch=0;
	while(ch!='-'&&(ch<'0'||ch>'9'))ch=getchar();
	if(ch=='-')w=-1,ch=getchar();
	while(ch>='0'&&ch<='9')data=((T)data<<3)+((T)data<<1)+(ch^'0'),ch=getchar();
	x=data*w;
}
template<typename T> inline void write(T x,char ch='\0')
{
	if(x<0)putchar('-'),x=-x;
	if(x>9)write(x/10);
	putchar(x%10+'0');
	if(ch!='\0')putchar(ch);
}
template<typename T> inline void chkmin(T &x,T y){x=(y<x?y:x);}
template<typename T> inline void chkmax(T &x,T y){x=(y>x?y:x);}
template<typename T> inline T min(T x,T y){return x<y?x:y;}
template<typename T> inline T max(T x,T y){return x>y?x:y;}
inline void insert(int x,int y,int z,db k)
{
	to[++e]=y;
	nex[e]=beg[x];
	beg[x]=e;
	cap[e]=z;
	was[e]=k;
	to[++e]=x;
	nex[e]=beg[y];
	beg[y]=e;
	cap[e]=0;
	was[e]=-k;
}
inline bool bfs()
{
	for(register int i=1;i<=n+n+2;++i)level[i]=doubleinf;
	level[s]=0;
	p[s]=1;
	q.push(s);
	while(!q.empty())
	{
		int x=q.front();
		q.pop();
		p[x]=0;
		for(register int i=beg[x];i;i=nex[i])
			if(cap[i]&&level[to[i]]>level[x]+was[i])
			{
				level[to[i]]=level[x]+was[i];
				if(!p[to[i]])
				{
					p[to[i]]=1;
					q.push(to[i]);
				}
			}
	}
	return level[t]!=doubleinf;
}
inline int dfs(int x,int maxflow)
{
	if(x==t||!maxflow)return maxflow;
	vis[x]=clk;
	int res=0,f;
	for(register int &i=cur[x];i;i=nex[i])
		if((vis[x]^vis[to[i]])&&cap[i]&&level[to[i]]==level[x]+was[i])
		{
			f=dfs(to[i],min(maxflow,cap[i]));
			maxflow-=f;
			res+=f;
			cap[i]-=f;
			cap[i^1]+=f;
			ans+=(db)f*was[i];
			if(!maxflow)break;
		}
	vis[x]=0;
	return res;
}
inline int MCMF()
{
	int res=0;
	while(bfs())clk++,memcpy(cur,beg,sizeof(cur)),res+=dfs(s,intinf);
	ans-=(db)res*100;
	return res;
}
int main()
{
	read(n);
	for(register int i=1;i<=n;++i)
		for(register int j=1;j<=n;++j)
		{
			int x;read(x);
			if(x)insert(i,n+j,1,-(db)log((db)x/100)/(db)log(10)+100);
		}
	s=n+n+1,t=s+1;
	for(register int i=1;i<=n;++i)insert(s,i,1,0),insert(i+n,t,1,0);
	if(MCMF()!=n)puts("0.0000000");
	else printf("%.7f\n",pow(10,-ans)*100);
	return 0;
}
posted @ 2018-05-29 20:23  HYJ_cnyali  阅读(217)  评论(0编辑  收藏  举报