Coding Contest【TLE是因为精度问题】【最大流最小费用】

HDU 5988 题目链接


  很容易想到的是最大流最小费用例子,但是呢,先不说一直TLE的原因,怎么才能把1-x_{1} * x_{2} * \cdots *x_{k}的最小值给求出来呢,其实就是相当于去求x_{1} * x_{2} * \cdots *x_{k}的最大值,但是网络流解决的是和的形式,怎样去解决呢?直接上log吧!变成了log(x_1) + log(x_{2}) + \cdots + log(x_{k})的最大值,如此,不如再取个负号,变成求log(x_1) - log(x_{2}) - \cdots - log(x_{k})的最大值了,那么就是可以用最小费用流来求解了。最后得到的MaxFlow_MinCost要去做1-pow(2, MaxFlow_MinCost)变回原来的乘积形式。

  当然,只有这么一个点是远远不够的!会发现,得到的答案会T,那是因为再跑流的判断的时候,我们用比较函数,一般是写成dist[v] > dist[u] + c就可以了吧、或者是势函数形式下的dist[v] > dist[u] + c + h[u] - h[v]来进行是否需要进队的运算的,但是这样的可能会存在环,原因在于这里是小数。那么,我们可以加入一个极小值efs来改变这个情况。

dist[v] > dist[u] + c + h[u] - h[v] + efs

或者是

dist[v] > dist[u] + c + efs

就可以解决这样的TLE问题了,并且以后需要牢牢的记住了!

#include <iostream>
#include <cstdio>
#include <cmath>
#include <string>
#include <cstring>
#include <algorithm>
#include <limits>
#include <vector>
#include <stack>
#include <queue>
#include <set>
#include <map>
#define lowbit(x) ( x&(-x) )
#define pi 3.141592653589793
#define e 2.718281828459045
//#define INF 0x3f3f3f3f
#define efs 1e-7
#define INF 1e9 + 7.
#define HalF (l + r)>>1
#define lsn rt<<1
#define rsn rt<<1|1
#define Lson lsn, l, mid
#define Rson rsn, mid+1, r
#define QL Lson, ql, qr
#define QR Rson, ql, qr
#define myself rt, l, r
using namespace std;
typedef unsigned long long ull;
typedef unsigned int uit;
typedef long long ll;
const int maxN = 107, S = 0;
int N, M, ED;
struct Eddge
{
    int nex, u, v, flow;
    double cost;
    Eddge(int _nex = -1, int _u = 0, int _v = 0, int _f = 0, double _c = 0.):nex(_nex), u(_u), v(_v), flow(_f), cost(_c) {}
};
vector<Eddge> E[maxN];
inline void _add(int u, int v, int flow, double cost)
{
    E[u].push_back(Eddge((int)E[v].size(), u, v, flow, cost));
    E[v].push_back(Eddge((int)E[u].size() - 1, v, u, 0, -cost));
}
struct node
{
    int id; double val;
    node(int a=0, double b=0.):id(a), val(b) {}
    friend bool operator < (node e1, node e2) { return e1.val > e2.val; }
};
int preP[maxN], preE[maxN];
double h[maxN], dist[maxN];
priority_queue<node> Q;
inline double MaxFlow_MinCost(int Flow)
{
    double ans = 0.;
    for(int i=0; i<=ED; i++) h[i] = 0.;
    while(Flow)
    {
        while(!Q.empty()) Q.pop();
        for(int i=0; i<=ED; i++) dist[i] = INF;
        dist[S] = 0.; Q.push(node(S, 0.));
        node now;
        while(!Q.empty())
        {
            now = Q.top(); Q.pop();
            int u = now.id;
            if(dist[u] < now.val) continue;
            int len = (int)E[u].size();
            for(int i=0, v, f; i<len; i++)
            {
                v = E[u][i].v; f = E[u][i].flow;
                double c = E[u][i].cost;
                if(f && dist[v] > dist[u] + c + h[u] - h[v] + efs)
                {
                    dist[v] = dist[u] + c + h[u] - h[v];
                    preP[v] = u; preE[v] = i;
                    Q.push(node(v, dist[v]));
                }
            }
        }
        if(dist[ED] == INF) break;
        for(int i=0; i<=ED; i++) h[i] += dist[i];
        int Capa = Flow;
        for(int u = ED; u; u = preP[u]) Capa = min(Capa, E[preP[u]][preE[u]].flow);
        Flow -= Capa;
        ans += Capa * h[ED];
        for(int u = ED; u; u = preP[u])
        {
            Eddge &G = E[preP[u]][preE[u]];
            G.flow -= Capa;
            E[G.v][G.nex].flow += Capa;
        }
    }
    return ans;
}
int main()
{
    int T; scanf("%d", &T);
    while(T--)
    {
        scanf("%d%d", &N, &M); ED = N + 1;
        for(int i=0; i<=ED; i++) E[i].clear();
        int sum = 0;
        for(int i=1, s, b; i<=N; i++)
        {
            scanf("%d%d", &s, &b); sum += s;
            _add(S, i, s, 0.);
            _add(i, ED, b, 0.);
        }
        for(int i=1, u, v, f; i<=M; i++)
        {
            double c;
            scanf("%d%d%d%lf", &u, &v, &f, &c);
            _add(u, v, 1, 0.);
            if(f > 1) _add(u, v, f - 1, -log2(1. - c));
        }
        printf("%.2lf\n", 1. - pow(2., -MaxFlow_MinCost(sum)));
    }
    return 0;
}

 

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Wuliwuliii

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值