HDU-5988 Coding Contest

这个题真的又长见识了。题目要求破坏最小的概率,我们可以求出不被破坏的最大概率,因为要乘积最大,所以我们可以取对数变成加。然后跑最大费用最大流就可以了。
然后一直T到死。这里需要加一个eps剪枝,在spfa中,不然就T到死。

#include <cstdio>
#include <queue>
#include <cmath>
using namespace std;
const int MAXN = 100+5;
const double inf = 1e300;
const double eps = 1e-6;
int n,m;
int s,e;
int cnt,head[MAXN];

struct node
{
    int u,v,f,next;
    double w;
} edge[30000];

void init()
{
    cnt = 0;
    for(int i = 0; i <= e; ++i)head[i] = -1;
}

void add(int u,int v,double w,int f)
{
    edge[cnt].u = u;
    edge[cnt].v = v;
    edge[cnt].w = w;
    edge[cnt].f = f;
    edge[cnt].next = head[u];
    head[u] = cnt++;
    edge[cnt].u = v;
    edge[cnt].v = u;
    edge[cnt].w = -w;
    edge[cnt].f = 0;
    edge[cnt].next = head[v];
    head[v] = cnt++;
}

bool vis[MAXN];
double dis[MAXN];
int pre[MAXN];
bool spfa()
{
    for(int i = 0; i <= e; ++i)
    {
        dis[i] = inf;
        pre[i] = -1;
    }
    queue<int>q;
    q.push(s);
    dis[s] = 0;
    while(!q.empty())
    {
        int u = q.front();
        q.pop();
        vis[u] = 0;
        for(int i = head[u]; i != -1; i = edge[i].next)
        {
            int v = edge[i].v;
            double w = edge[i].w;
            int f = edge[i].f;
            if(f > 0 && dis[v] - dis[u] - w > eps)
            {
                dis[v] = dis[u] + w;
                pre[v] = i;
                if(!vis[v])
                {
                    vis[v] = 1;
                    q.push(v);
                }
            }
        }
    }
    if(pre[e] == -1)return 0;
    return 1;
}

double get_mincost()
{
    double min_cost = 0;
    while(spfa())
    {
        int p = pre[e];
        int flow = 200000;
        while(p != -1)
        {
            flow = flow < edge[p].f?flow : edge[p].f;
            p = pre[edge[p].u];
        }
        min_cost += flow*dis[e];
        if(pow(2,-min_cost) <= 0.005)break;
        p = pre[e];
        while(p != -1)
        {
            edge[p].f -= flow;
            edge[p^1].f += flow;
            p = pre[edge[p].u];
        }
    }
    return min_cost;
}

int main()
{
    int t;
    scanf("%d",&t);
    while(t--)
    {
        scanf("%d%d",&n,&m);
        s = 0,e = n+1;
        init();
        int a,b;
        for(int i = 1; i <= n; ++i)
        {
            scanf("%d%d",&a,&b);
            add(s,i,0,a-b);
            add(i,e,0,b-a);
        }
        int u,v,f;
        double w;
        while(m--)
        {
            scanf("%d%d%d%lf",&u,&v,&f,&w);
            add(u,v,0,1);
            add(u,v,-log2(1.0-w),f-1);
        }
        printf("%.2f\n",1-pow(2,-get_mincost()));
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值