Delivery Bears(二分 + 最大流)

Niwel is a little golden bear. As everyone knows, bears live in forests, but Niwel got tired of seeing all the trees so he decided to move to the city.

In the city, Niwel took on a job managing bears to deliver goods. The city that he lives in can be represented as a directed graph with n nodes and m edges. Each edge has a weight capacity. A delivery consists of a bear carrying weights with their bear hands on a simple path from node 1 to node n. The total weight that travels across a particular edge must not exceed the weight capacity of that edge.

Niwel has exactly x bears. In the interest of fairness, no bear can rest, and the weight that each bear carries must be exactly the same. However, each bear may take different paths if they like.

Niwel would like to determine, what is the maximum amount of weight he can deliver (it's the sum of weights carried by bears). Find the maximum weight.

Input

The first line contains three integers nm and x (2 ≤ n ≤ 50, 1 ≤ m ≤ 500, 1 ≤ x ≤ 100 000) — the number of nodes, the number of directed edges and the number of bears, respectively.

Each of the following m lines contains three integers aibi and ci (1 ≤ ai, bi ≤ nai ≠ bi, 1 ≤ ci ≤ 1 000 000). This represents a directed edge from node ai to bi with weight capacity ci. There are no self loops and no multiple edges from one city to the other city. More formally, for each i and j that i ≠ j it's guaranteed that ai ≠ aj or bi ≠ bj. It is also guaranteed that there is at least one path from node 1 to node n.

Output

Print one real value on a single line — the maximum amount of weight Niwel can deliver if he uses exactly x bears. Your answer will be considered correct if its absolute or relative error does not exceed 10 - 6.

Namely: let's assume that your answer is a, and the answer of the jury is b. The checker program will consider your answer correct if .

Examples

Input

4 4 3
1 2 2
2 4 1
1 3 1
3 4 2

Output

1.5000000000

Input

5 11 23
1 2 3
2 3 4
3 4 5
4 5 6
1 3 4
2 4 5
3 5 6
1 4 2
2 5 3
1 5 2
3 2 30

Output

10.2222222222

Note

In the first sample, Niwel has three bears. Two bears can choose the path , while one bear can choose the path . Even though the bear that goes on the path  can carry one unit of weight, in the interest of fairness, he is restricted to carry 0.5 units of weight. Thus, the total weight is 1.5 units overall. Note that even though Niwel can deliver more weight with just 2 bears, he must use exactly 3 bears on this day.

题意:有n个点,m条路,x只熊。每条路有三个参数,u(起点),v(终点),c(容量)。Niwel想要监督所有熊把东西从1点搬到n点,每只熊都要搬相同多的货物,问最大能搬多少货物。

思路:乍一看,最大流。emmm... 好了,我们看题:x只熊,每只熊都要搬东西,且要搬相同重量的东西。那么我们可以利用二分枚举所有熊要搬的总重量,然后算出每只熊要搬的平均重量。然后我们就可以对边进行操作了,每条边原有一个容量,如果我们让这个容量除以每只熊要搬的重量,那么边的容量就转变成这条路最多能走多少只熊,然后我们再通过最大流算出参与搬运的熊的总数,只要大于熊数x,就代表这个值可以执行,继续二分枚举,确保精度。

代码如下:

#include<cstdio>
#include<cmath>
#include<cstring>
#include<queue>
#include<algorithm>
#define N 510
#define MAXN 100010
#define inf 0x3f3f3f3f
#define LL long long
using namespace std;
struct node
{
    LL c,f;
} Edge[N][N];

int n,m,s,t;
LL Map[N][3];
LL residual[N][N];
int pre[N],vis[N];
LL max_flow,min_augment; //切记long long

void find_augment_path()//找增广路
{
    memset(pre,0,sizeof(pre));
    memset(vis,0,sizeof(vis));
    memset(residual,0,sizeof(residual));
    queue<int>Q;
    Q.push(1);
    vis[1]=1,pre[1]=1;
    while(!Q.empty()&&!pre[t])
    {
        int cu=Q.front();
        Q.pop();
        for(int i=1; i<=t; i++)
        {
            if(!vis[i])
            {
                if(Edge[cu][i].c>Edge[cu][i].f)
                {
                    residual[cu][i]=Edge[cu][i].c-Edge[cu][i].f;
                    pre[i]=cu,vis[i]=1,Q.push(i);
                }
                else if(Edge[i][cu].f>0)
                {
                    residual[cu][i]=Edge[i][cu].f;
                    pre[i]=cu,vis[i]=1,Q.push(i);
                }
            }
        }
    }
}

void augment_flow()
{
    int i=t;
    LL j=inf;
    if(!pre[i])
    {
        min_augment=0;
        return;
    }
    while(i!=1)
    {
        if(residual[pre[i]][i]<j)
            j=residual[pre[i]][i];
        i=pre[i];
    }
    min_augment=j;
}
void update_flow()
{
    int i=t;
    if(!pre[i])
        return;
    while(i!=1)
    {
        if(Edge[pre[i]][i].c>Edge[pre[i]][i].f)
            Edge[pre[i]][i].f+=min_augment;
        else if(Edge[i][pre[i]].f>0)
            Edge[pre[i]][i].f+=min_augment;
        i=pre[i];
    }
}
void solve()
{
    max_flow=0;
    while(1)
    {
        find_augment_path();
        augment_flow();
        if(min_augment!=0)
        {
            max_flow+=min_augment;
            update_flow();
        }
        else break;
    }
}

int work(double num)
{
    double p=num/(n+0.0);//每只熊平均要搬运的货物
    memset(Edge,0,sizeof(Edge));//初始化流及容量
    for(int i=0; i<m; i++)
    {
        LL u=Map[i][0];
        LL v=Map[i][1];
        LL c=Map[i][2];
        Edge[u][v].c=floor(1.0*c/p);//更改流及容量,此时的容量为这条路上最多能过多少只熊
    }
    solve();//最大流
    if(max_flow>=n)
        return 1;
    return 0;
}
int main()
{
    scanf("%d%d%d",&t,&m,&n);
    for(int i=0; i<m; i++)
    {
        LL u,v,c;
        scanf("%lld%lld%lld",&u,&v,&c);
        Map[i][0]=u,Map[i][1]=v,Map[i][2]=c;//先用二维数组储存边的数据
    }
    double l=0.0,r=1e12;
    int k=200;
    while(k--)//二分枚举200次,确保精度
    {
        double mid=(l+r)/2.0;
        if(work(mid))
            l=mid;
        else
            r=mid;
    }
    double tmp;
    if(work(r))
        tmp=r;
    else
        tmp=l;
    printf("%.10f\n",tmp);
}

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值