2016ACM/ICPC亚洲区青岛站 Coding Contest 费用流

目录

  • 2016ACM/ICPC亚洲区青岛站 Coding Contest 费用流

    • 题目描述
    • 题意(博主的鬼畜翻译):
    • 分析:
    • 代码

2016ACM/ICPC亚洲区青岛站 Coding Contest 费用流

题目描述

题目描述
    A coding contest will be held in this university, in a huge playground. The whole playground would be divided into N blocks, and there would be M directed paths linking these blocks. The i-th path goes from the ui-th block to the vi-th block. Your task is to solve the lunch issue. According to the arrangement, there are si competitors in the i-th block. Limited to the size of table, bi bags of lunch including breads, sausages and milk would be put in the i-th block. As a result, some competitors need to move to another block to access lunch. However, the playground is temporary, as a result there would be so many wires on the path.
    For the i-th path, the wires have been stabilized at ?rst and the ?rst competitor who walker through it would not break the wires. Since then, however, when a person go through the i?th path, there is a chance of pi to touch the wires and a?ect the whole networks. Moreover, to protect these wires, no more than ci competitors are allowed to walk through the i-th path.
    Now you need to ?nd a way for all competitors to get their lunch, and minimize the possibility of network crashing.
输入描述:
    The ?rst line of input contains an integer t which is the number of test cases. Then t test cases follow.
    For each test case, the ?rst line consists of two integers N (N ≤ 100) and M (M ≤ 5000). Each of the next N lines contains two integers si and bi (si,bi ≤ 200).
    Each of the next M lines contains three integers ui,vi and ci(ci ≤ 100) and a ?oat-point number pi(0 < pi < 1). It is guaranteed that there is at least one way to let every competitor has lunch.
输出描述:
    For each turn of each case, output the minimum possibility that the networks would break down. Round it to 2 digits.

题意(博主的鬼畜翻译):

有n个点,m条边,每个点有\(a_i\)竞争者,和\(b_i\)的食物,每个人要吃饭,可以通过一些路径。每条路径电线有\(p_i\)的概率碰坏,第一个人一定不会坏。问怎么走每个人都能获得食物,切坏的概率最小。

分析:

首先这个输入u -> v 花费 \(c_i\) 概率 \(p_i\) 费用流的输入还是很好看出来的。

  1. 源点连每个点(1~n) 流量人数,费用零
  2. 每个点(1~n)连汇点,流量食物,费用零
    【1】
    这样问题就变成了源点到汇点的费用表示的概率最小了。都是题目的概率计数是乘法,而费用流中是加法。这里需要转化成log的形式log(ab) = log(a) + log(b) 这样结果最后求一个exp(x)就好了。
    【2】
    第二点,坏的概率你不知道具体是路径中那一条边坏了。如果把问题转化成最大的不坏的概率,就变成路径中每条路都不坏,那么概率就得以统一。
    因此
    对于u->v 容量c, 概率p
    建边 u->v, 流量c, 费用-log(1-p)
    ps:最大费用最大流和最小费用最大流的区别就是加边加个符号,结果反一下。
    【3】
    然后还有第三个问题:第一个人一定不会喷坏,那么我们拆边即可。这个相比前面反而是小问题了。

写的时候,代码spfa中有个地方没写EPS,TLE了不知道为什么,然后浮点费用流注意板子中int该改的要全改了。

代码

///2016ACM/ICPC亚洲区青岛站 Coding Contest 费用流
#include <bits/stdc++.h>

using namespace std;

const double EPS = 1e-4;

struct MCMF {

    static const int MAXN = 200;
    static const int MAXM = 10000;
    static const int INF = 1e9 + 7;
    static const int INF0X3F = 0x3f3f3f3f;

    int n, m, first[MAXN], s, t, sign;

    double dist[MAXN];

    int inq[MAXN], pre[MAXN], incf[MAXN];

    int max_flow;

    double min_cost;

    struct Edge {
        int to, cap, next;
        double cost;
    } edge[MAXM * 4];

    void init(int l, int r, int ss, int tt) {
        memset(first, -1, sizeof(first));
        s = ss, t = tt, sign = 0;
        max_flow = min_cost = 0;
    }

    void add_edge(int u, int v, int cap, double cost) {
        edge[sign].to = v, edge[sign].cap = cap, edge[sign].cost = cost;
        edge[sign].next = first[u], first[u] = sign++;
        edge[sign].to = u, edge[sign].cap = 0, edge[sign].cost = -cost;
        edge[sign].next = first[v], first[v] = sign++;
    }

    bool spfa(int s, int t) {
        for(int i = 0; i < MAXN; i++ ) {
            dist[i] = INF;
            inq[i] = 0;
            pre[i] = -1;
        }
        queue<int>que;
        que.push(s), inq[s] = 1, dist[s] = 0;
        incf[s] = INF0X3F;
        while(!que.empty()) {
            int now = que.front();
            que.pop();
            inq[now] = 0;
            for(int i = first[now]; ~i; i = edge[i].next) {
                int to = edge[i].to, cap = edge[i].cap;
                double cost = edge[i].cost;
                ///不加EPS T了?
                if(cap > 0 && dist[to] > dist[now] + cost + EPS) {
                    dist[to] = dist[now] + cost;
                    incf[to] = min(incf[now], cap);
                    pre[to] = i;
                    if(!inq[to]) {
                        que.push(to);
                        inq[to] = 1;
                    }
                }
            }
        }
        return fabs(dist[t] - INF) > EPS;
    }

    void update(int s, int t) {
        int x = t;
        while(x != s) {
            int pos = pre[x];
            edge[pos].cap -= incf[t];
            edge[pos ^ 1].cap += incf[t];
            x = edge[pos ^ 1].to;
        }
        max_flow += incf[t];
        min_cost += dist[t] * incf[t];
    }

    void minCostMaxFlow(int s, int t) {
        while(spfa(s, t)) {
            update(s, t);
        }
    }

} cwl;

int main() {
    int t, n, m;
    scanf("%d", &t);
    while(t--) {
        scanf("%d %d", &n, &m);
        cwl.init(0, n + 1, 0, n + 1);
        for(int i = 1; i <= n; i++ ) {
            int a, b;
            scanf("%d %d", &a, &b);
            if(a) {
                cwl.add_edge(0, i, a, 0);
            }
            if(b) {
                cwl.add_edge(i, n + 1, b, 0);
            }
        }
        for(int i = 1; i <= m; i++ ) {
            int u, v, cap;
            double cost;
            scanf("%d %d %d %lf", &u, &v, &cap, &cost);
            cost = -log(1 - cost);
            cwl.add_edge(u, v, 1, 0);
            cwl.add_edge(u, v, cap - 1, cost);
        }
        cwl.minCostMaxFlow(0, n + 1);
        printf("%.2f\n", 1 - exp(-cwl.min_cost));
    }
    return 0;
}

原文地址:https://www.cnblogs.com/Q1143316492/p/9751794.html

时间: 2024-10-08 09:20:43

2016ACM/ICPC亚洲区青岛站 Coding Contest 费用流的相关文章

2016ACM/ICPC亚洲区青岛站 B Hdu-5983 Pocket Cube 模拟

题面 题意:给你一个2*2的魔方,给你每个面每个小块的颜色,一共24个,然后问你能否在一步之内还原. 题解:手动在纸上画,推出每种变化对应的置换,显然,一共有6种,而且可以当成3种,(具体哪3种,就是绕x,y,z轴转一次的),另外一个方向,就是转三次就行了 而且你也不需要考虑什么上面转了下面转,相对关系是一样的 写的时候犯了个错,手写的u,v,r分不清楚了..... 转一次会有12个小面发生变化,写的时候可以只写8个面,因为有一个面的位置变了, 但是我们只问一步之内能不能还原,那一面的都没有到其

HDU 5976 Detachment 【贪心】 (2016ACM/ICPC亚洲区大连站)

Detachment Time Limit: 4000/2000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others)Total Submission(s): 570    Accepted Submission(s): 192 Problem Description In a highly developed alien society, the habitats are almost infinite dimensiona

HDU 5950 Recursive sequence 【递推+矩阵快速幂】 (2016ACM/ICPC亚洲区沈阳站)

Recursive sequence Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others)Total Submission(s): 249    Accepted Submission(s): 140 Problem Description Farmer John likes to play mathematics games with his N cows. Recently, t

2016 ACM/ICPC亚洲区青岛站现场赛(部分题解)

摘要 本文主要列举并求解了2016 ACM/ICPC亚洲区青岛站现场赛的部分真题,着重介绍了各个题目的解题思路,结合详细的AC代码,意在熟悉青岛赛区的出题策略,以备战2018青岛站现场赛. HDU 5984 Pocky 题意 给出一根棒子(可以吃的)的长度x和切割过程中不能小于的长度d,每次随机的选取一个位置切开,吃掉左边的一半,对右边的棒子同样操作,直至剩余的长度不大于d时停止.现在给出x和d,问切割次数的数学期望是多少. 解题思路 当看到第二个样例2 1时,结果是1.693147,联想到ln

HDU 5988 Coding Contest(费用流+浮点数)

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=5988 题目大意: 给定n个点,m条有向边,每个点是一个吃饭的地方,每个人一盒饭.每个点有S个人,有B盒饭.每条边只能被走c次,每条边上都有电线,第一个人通过的时候,不会破坏电线,从第二个人开始,每次都有概率p破坏掉电线.使得每个人都能吃饭,求最小破坏电线的概率. 解题思路: 题目要求我们求最小破坏电线的概率,就是一个最小乘积问题,加上log可以将其转变为加法,那样就可以使用费用刘来解决了. 按以下方

2016ACM/ICPC亚洲区大连站-重现赛

题目链接:http://acm.hdu.edu.cn/search.php?field=problem&key=2016ACM%2FICPC%D1%C7%D6%DE%C7%F8%B4%F3%C1%AC%D5%BE-%D6%D8%CF%D6%C8%FC%A3%A8%B8%D0%D0%BB%B4%F3%C1%AC%BA%A3%CA%C2%B4%F3%D1%A7%A3%A9&source=1&searchmode=source A.染色乱搞. 1 #include <bits/st

2016ACM/ICPC亚洲区大连站-重现赛(感谢大连海事大学)(6/10)

1001题意:n个人,给m对敌对关系,X个好人,Y个坏人.现在问你是否每个人都是要么是好人,要么是坏人. 先看看与X,Y个人有联通的人是否有矛盾,没有矛盾的话咋就继续遍历那些不确定的人关系,随便取一个数3,与其相连的就是4,间隔就要相同,dfs搜过去就可以判断了 #include<bits/stdc++.h> using namespace std; #pragma comment(linker, "/STACK:102400000,102400000") #define

2016ACM/ICPC亚洲区沈阳站-重现赛

C.Recursive sequence 求ans(x),ans(1)=a,ans(2)=b,ans(n)=ans(n-2)*2+ans(n-1)+n^4 如果直接就去解...很难,毕竟不是那种可以直接化成矩阵的格式,我们也因为这个被卡很长时间 事实上可以把这道式子化成几个基本元素的格式,然后就容易组合了,比如ans(n-2)*2+ans(n-1)+(n-1)^4+4*(n-1)^3+6*(n-1)^2+4*(n-1)^1+1 包含了所有的基本组成形式,化绝对为相对,并且除了一个n-2其他都是n

HDU 5950 - Recursive sequence - [矩阵快速幂加速递推][2016ACM/ICPC亚洲区沈阳站 Problem C]

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=5950 Farmer John likes to play mathematics games with his N cows. Recently, they are attracted by recursive sequences. In each turn, the cows would stand in a line, while John writes two positive numbers