P4329 [COCI2006-2007#1] Bond

本文介绍了一种使用最大费用流算法解决任务分配问题的方法,具体地,通过构建带权二分图并采用KM算法来寻找使所有任务成功完成概率最大的人员分配方案。

题意翻译

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

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

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

题目描述

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.

 

Solution:

  本题SB费用流,裸的没话讲咯。

  读题后不难构建一个带权二分图的模型,于是KM啦,我们直接跑最大费用最大流,坑点在于直接累乘费用会爆精度(long double都炸了),一个巧妙的解决方法是建图时把费用设为$\ln c$,这样跑费用流就把乘法变为加法,最后只要输出$e^{cost_{max}}$就好了(注意特判$cost_{max}=0$的情况)。

代码:

/*Code by 520 -- 9.4*/
#include<bits/stdc++.h>
#define il inline
#define ll long long
#define RE register
#define For(i,a,b) for(RE int (i)=(a);(i)<=(b);(i)++)
#define Bor(i,a,b) for(RE int (i)=(b);(i)>=(a);(i)--)
using namespace std;
const int N=100005,inf=23333333;
int s,t,n,maxf,h[N],to[N],net[N],w[N],cnt=1,pre[N],maxn[N];
long double ans,dis[N],c[N];
bool vis[N];

il void add(int u,int v,int fl,double co){
    to[++cnt]=v,net[cnt]=h[u],w[cnt]=fl,c[cnt]=co,h[u]=cnt;
    to[++cnt]=u,net[cnt]=h[v],w[cnt]=0,c[cnt]=-co,h[v]=cnt;
}

il bool spfa(){
    queue<int>q;
    For(i,1,t) dis[i]=-inf;
    dis[s]=0,q.push(s),maxn[s]=inf;
    while(!q.empty()){
        RE int u=q.front();q.pop();vis[u]=0;
        for(RE int i=h[u];i;i=net[i])
            if(dis[to[i]]<dis[u]+c[i]&&w[i]){
                dis[to[i]]=dis[u]+c[i],pre[to[i]]=i,
                maxn[to[i]]=min(maxn[u],w[i]);
                if(!vis[to[i]])vis[to[i]]=1,q.push(to[i]);
            }
    }
    return dis[t]!=-inf;
}

il void update(){
    int p=t;
    while(p!=s){
        RE int i=pre[p];
        w[i]-=maxn[t],w[i^1]+=maxn[t];
        p=to[i^1];
    }
    ans+=dis[t];
}

int main(){
    scanf("%d",&n),t=n<<1|1;
    double x;
    For(i,1,n) For(j,1,n) scanf("%lf",&x),add(i,j+n,1,log(x/100));
    For(i,1,n) add(s,i,1,0),add(i+n,t,1,0);
    while(spfa())update();
    printf("%.6Lf",(ans?exp(ans)*100:0));
    return 0;
}

 

 

转载于:https://www.cnblogs.com/five20/p/9588998.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值