bzoj 2542: [Ctsc2001]终极情报网 费用流

题目链接

2542: [Ctsc2001]终极情报网

Time Limit: 1 Sec  Memory Limit: 128 MB
Submit: 321  Solved: 125
[Submit][Status][Discuss]

Description

在最后的诺曼底登陆战开始之前,盟军与德军的情报部门围绕着最终的登陆地点展开了一场规模空前的情报战。 
这场情报战中,盟军的战术是利用那些潜伏在敌军内部的双重间谍,将假的登陆消息发布给敌军的情报机关的负责人。那些已经潜入敌后的间谍们都是盟军情报部的精英,忠实可靠;但是如何选择合适的人选,以及最佳的消息传递方法,才能保证假消息能够尽快而且安全准确地传递到德军指挥官们的耳朵里,成了困扰盟军情报部长的最大问题。他需要你的帮助。

以下是情报部长提供的作战资料:

在敌后一共潜伏着我方最优秀的N名间谍,分别用数字1, 2, …, N编号。在给定的作战时间内,任意两人之间至多只进行一次点对点的双人联系。 
我将给你一份表格,表格中将提供任意两位间谍i和j之间进行联系的安全程度,用一个 [0, 1] 的实数Si j表示;以及他们这次联系时,能够互相传递的消息的最大数目,用一个正整数表示Mi j (如果在表格中没有被提及,那么间谍i和j之间不进行直接联系)。 
假消息从盟军总部传递到每个间谍手里的渠道也不是绝对安全,我们用 [0, 1] 的实数ASj表示总部与间谍j之间进行联系的安全程度,AMj则表示总部和间谍j之间进行联系时传递的消息的最大数目。对于不和总部直接联系的间谍,他的AMj=0(而表格中给出的他的ASj是没有意义的)。 
当然,假消息从间谍手中交到敌军的情报部官员的办公桌上的过程是绝对安全的,也即是说,间谍与敌军情报部门之间要么不进行直接联系,要么其联系的安全程度是1(即完全可靠)。

现在情报部打算把K条假消息“透露”到德军那里。消息先由总部一次性发给N名间谍中的一些人,再通过他们之间的情报网传播,最终由这N名间谍中的某些将情报送到德军手中。 
对于一条消息,只有安全的通过了所有的中转过程到达敌军情报部,这个传递消息的过程才算是安全的;因此根据乘法原理,它的安全程度P就是从总部出发,经多次传递直到到达德军那里,每一次传递该消息的安全程度的乘积。 
而对于整个计划而言,只有当N条消息都安全的通过情报网到达德军手中,没有一条引起怀疑时,才算是成功的。所以计划的可靠程度是所有消息的安全程度的乘积。 
显然,计划的可靠性取决于这些消息在情报网中的传递方法。 
我需要一个方案,确定消息应该从哪些人手中传递到哪些人手中,使得最终计划的可靠性最大。

你可以利用计算机,来求得这个最可靠的消息传递方案。

Input

第一行包括两个整数N和K,分别是间谍的总人数和计划包含的消息总数。 
第二行包括2N个数,前N个数是实数AS1, AS2, …, ASN(范围在[0, 1]以内);后N个数是整数AM1, AM1, …, AMN。 
第三行包含了N个整数,其中第i(i = 1, 2, …, N)个整数如果为0表示间谍i与德军情报部不进行联系,如果为1则表示间谍与德军情报部进行联系。 
第四行开始,每行包括4个数,依次分别是:代表间谍编号的正整数i和j,间谍i和j联系的安全性参数Si j([0,1]范围内的实数),以及i、j之间传递的最大消息数 Mi j(每一行的i均小于j )。 
最后的一行包含两个整数-1 -1,表示输入数据的结束。 
0

Output

只有一行。这一行中包含一个实数P,给出的是整个计划的可靠程度P,保留5位有效数字(四舍五入)。 
如果情报网根本不能将K条消息传到德军手中,那么计划的可靠性为0。 
(你可以假定,如果计划存在,那么它的可靠性大于1e-12)

Sample Input

6 13
0.9 0.7 0.8 0 0 0 2 6 8 0 0 0
0 0 0 1 0 1
1 4 0.5 2
2 3 0.9 5
2 5 0.8 2
2 6 0.8 7
3 5 0.8 2
5 6 0.8 4
-1 -1

Sample Output

0.00021184

因为是累乘, 所以把边的费用变为log就可以了。 5位有效数字有点坑...看的别人的代码。

#include <iostream>
#include <vector>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
#include <map>
#include <set>
#include <string>
#include <queue>
#include <stack>
#include <bitset>
using namespace std;
#define pb(x) push_back(x)
#define ll long long
#define mk(x, y) make_pair(x, y)
#define lson l, m, rt<<1
#define mem(a) memset(a, 0, sizeof(a))
#define rson m+1, r, rt<<1|1
#define mem1(a) memset(a, -1, sizeof(a))
#define mem2(a) memset(a, 0x3f, sizeof(a))
#define rep(i, n, a) for(int i = a; i<n; i++)
#define fi first
#define se second
typedef pair<int, int> pll;
const double PI = acos(-1.0);
const double eps = 1e-6;
const int mod = 1e9+7;
const int inf = 1061109567;
const int dir[][2] = { {-1, 0}, {1, 0}, {0, -1}, {0, 1} };
const int maxn = 2e5+5;
int num, head[maxn*2], s, t, n, k, nn, flow, cnt, cap[maxn], q[maxn], cur[maxn], vis[maxn];
double cost, dis[maxn];
struct node
{
    int to, nextt, c;
    double w;
    node(){}
    node(int to, int nextt, int c, double w):to(to), nextt(nextt), c(c), w(w) {}
}e[maxn*2];
int spfa() {
    int st, ed;
    st = ed = 0;
    for(int i = 1; i<maxn; i++)
        dis[i] = -inf;
    ++cnt;
    dis[s] = 0;
    cap[s] = inf;
    cur[s] = -1;
    q[ed++] = s;
    while(st<ed) {
        int u = q[st++];
        vis[u] = cnt-1;
        for(int i = head[u]; ~i; i = e[i].nextt) {
            int v = e[i].to, c = e[i].c;
            double w = e[i].w;
            if(c && dis[v]<dis[u]+w&&fabs(dis[v]-dis[u]-w)>eps) {
                dis[v] = dis[u]+w;
                cap[v] = min(c, cap[u]);
                cur[v] = i;
                if(vis[v] != cnt) {
                    vis[v] = cnt;
                    q[ed++] = v;
                }
            }
        }
    }
    if(fabs(dis[t] + inf)<eps)
        return 0;
    cost += dis[t]*cap[t];
    flow += cap[t];
    for(int i = cur[t]; ~i; i = cur[e[i^1].to]) {
        e[i].c -= cap[t];
        e[i^1].c += cap[t];
    }
    return 1;
}
double mcmf() {
    flow = cost = 0;
    while(spfa())
        ;
    return cost;
}
void add(int u, int v, int c, double val) {
    e[num] = node(v, head[u], c, val); head[u] = num++;
    e[num] = node(u, head[v], 0, -val); head[v] = num++;
}
void init() {
    mem1(head);
    num = cnt = 0;
    mem(vis);
}
double a[maxn];
void deal(double ans){
    char ch[40];
    sprintf(ch,"%.15f\n",ans);
    int sum=0,i;
    for(i=0; sum<5; i++)
    {
        if((ch[i]!=‘0‘&&ch[i]!=‘.‘)|sum>0)
            sum++;
    }
    if(ch[i]>=‘5‘)
        ch[i-1]++;
    ch[i]=0;
    for(; i>=0; i--)
    {
        if(ch[i]==‘.‘)break;
        else if(ch[i]>‘9‘) {
            ch[i-1]++,ch[i]=‘0‘;
        }
    }
    printf("%s\n",ch);
}
int main()
{
    init();
    int n, m, ss, x;
    cin>>n>>m;
    s = 0, ss = n+1, t = n+2;
    add(s, ss, m, log(1.0));
    for(int i = 1; i<=n; i++) {
        scanf("%lf", &a[i]);
    }
    for(int i = 1; i<=n; i++) {
        scanf("%d", &x);
        if(x) {
            add(ss, i, x, log(a[i]));
        }
    }
    for(int i = 1; i<=n; i++) {
        scanf("%d", &x);
        if(x)
            add(i, t, m, log(1.0));
    }
    int y, y1;
    double x1;
    while(scanf("%d%d", &x, &y)) {
        if(x==-1&&y==-1)
            break;
        scanf("%lf%d", &x1, &y1);
        add(x, y, y1, log(x1));
        add(y, x, y1, log(x1));
    }
    double ans = mcmf();
    if(flow!=m) {
        puts("0.0000\n");
        return 0;
    } else {
        ans = exp(ans);
        deal(ans);
    }
    return 0;
}
时间: 2024-10-13 15:04:21

bzoj 2542: [Ctsc2001]终极情报网 费用流的相关文章

图论(网络流):[CTSC2001]终极情报网

[CTSC2001]终极情报网 [题目描述] 在最后的诺曼底登陆战开始之前,盟军与德军的情报部门围绕着最终的登陆地点展开了一场规模空前的情报战. 这场情报战中,盟军的战术是利用那些潜伏在敌军内部的双重间谍,将假的登陆消息发布给敌军的情报机关的负责人.那些已经潜入敌后的间谍们都是盟军情报部的 精英,忠实可靠:但是如何选择合适的人选,以及最佳的消息传递方法,才能保证假消息能够尽快而且安全准确地传递到德军指挥官们的耳朵里,成了困扰盟军情报 部长的最大问题.他需要你的帮助. 以下是情报部长提供的作战资料

BZOJ 2668 交换棋子(费用流)

题目链接:http://61.187.179.132/JudgeOnline/problem.php?id=2668 题意:有一个n行m列的黑白棋盘,你每次可以交换两个相邻格子中的棋子,最终达到目标状态.要求第i行第j列的格子只能参与m[i,j]次交换. 思路: 我们将1看做要移动的数字,将0看做空白.那么若1在始末状态个数不同则无解:如某个格子始末状态均有1则这个格子的1对结果无影响,可以将其都置为0.将每个格子拆为为个点p0,p1,p2: (1)若格子初始为1,则连边:<s,p0,1,0>

BZOJ 3171 循环格(费用流)

题目链接:http://61.187.179.132/JudgeOnline/problem.php?id=3171 题意: 思路:若能构成循环,则每个格子的入度出度 均为1.因此将每个点拆成两个点x1,x2,分别作为出点和入点.出点向周围四个点的入点连边,流1,费用视该格子的字母而定.该格子的字母正好是这个方 向则费用为0否则为1.原点S向每个出点连边,流量1费用0:每个入点向汇点连边,流量1费用0.求最小费用最大流即可. struct node { int u,v,next,cost,cap

BZOJ 1927: [Sdoi2010]星际竞速 费用流

1927: [Sdoi2010]星际竞速 Time Limit: 1 Sec Memory Limit: 256 MB 题目连接 http://www.lydsy.com/JudgeOnline/problem.php?id=1927 Description 10 年一度的银河系赛车大赛又要开始了.作为全银河最盛大的活动之一, 夺得这个项目的冠军无疑是很多人的梦想,来自杰森座 α星的悠悠也是其中之一. 赛车大赛的赛场由 N 颗行星和M条双向星际航路构成,其中每颗行星都有 一个不同的引力值.大赛要

BZOJ 1449 JSOI2009 球队收益 费用流

题目大意:给定n支球队,第i支球队已经赢了wini场,输了losei场,接下来还有m场比赛,每个球队最终的收益为Ci?x2i+Di?y2i,其中xi为最终的胜场,yi为最终的负场 求最小化收益 考虑一只球队,其收益与在接下来的比赛中的胜场数关系为: 赢0场 Ci?win2i+Di?(di+losei)2 赢1场 Ci?(wini+1)2+Di?(di+losei?1)2 赢2场 Ci?(wini+2)2+Di?(di+losei?2)2 - 赢di场 Ci?(wini+di)2+Di?lose2

[BZOJ 1070] [SCOI2007] 修车 【费用流】

题目链接:BZOJ - 1070 题目分析 首先想到拆点,把每个技术人员拆成 n 个点,从某个技术人员拆出的第 i 个点,向某辆车连边,表示这是这个技术人员修的倒数第 i 辆车.那么这一次修车对整个答案的贡献就是,i * Time[j][k]. j 是车的编号,k 是技术人员编号.因为这辆车以及之后这个人要修的车的等待时间都增加了 Time[j][k], 所以包括这辆车在内一共有 i 辆车的等待时间加上了这次修车的时间.这样倒着考虑就可以用边的费用很简便的表示修车使所有人增加的时间了.从 S 到

BZOJ 3171: [Tjoi2013]循环格( 费用流 )

每个点都在某个环中, 出度都为1, 只要让入度也全为1就可以满足题意了. 然后就是裸的最小费用最大流了. ---------------------------------------------------------------------------- #include<cstdio> #include<cstring> #include<algorithm> #include<deque> #include<bitset> using n

BZOJ 3308 九月的咖啡店 费用流

题目大意:在[1,n]区间内选择一些数,使得这些数两两互质,求这些数的和的最大值 容易发现对于一个最优解,每个质数存在且仅存在于一个数中.(废话. 但是有可能一个数中存在多个质数 下面是两个结论: 1.一个数中最多存在两个不同的质数 2.这两个质数一个<n√,一个>n√ 我完全不会证明这两个结论,这两个结论都是官方题解里的 然后就好办了,我们对于<n√的质数和>n√的质数建立二分图,求最大费用最大流即可 但是这样会T掉,因为图太大了 因此我们有两个剪枝: 1.对于>n2的质数

bzoj 2245: [SDOI2011]工作安排(费用流)

2245: [SDOI2011]工作安排 Time Limit: 20 Sec  Memory Limit: 512 MB Submit: 1446  Solved: 692 [Submit][Status][Discuss] Description 你的公司接到了一批订单.订单要求你的公司提供n类产品,产品被编号为1~n,其中第i类产品共需要Ci件.公司共有m名员工,员工被编号为1~m员工能够制造的产品种类有所区别.一件产品必须完整地由一名员工制造,不可以由某名员工制造一部分配件后,再转交给另