Codeforces--653D--Delivery Bears(二分+最大流)


Time Limit: 2000MS Memory Limit: 262144KB 64bit IO Format: %I64d & %I64u

 Status

Description

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 exactlyx 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 ≤ 501 ≤ m ≤ 5001 ≤ 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 ≠ bi1 ≤ 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 .

Sample Input

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
题意:n个点m条边,x只小熊,小熊要把东西从1点运到n点,但是每条边都有一定的权值,小熊运的东西不能超过边对应的权值,并且每只小熊搬运的东西都是一样的,每只小熊可能会选择不一样的路,求搬运的最多的货物有多少
明显是要二分的,每次枚举一个货物的重量,然后跑一边最大流,判断所有的小熊是否都可以到达,建图的时候可以加一步转化,把边权转化为最多通过的小熊的数量,最大流的返回值应该大于等于x
精度要考虑清楚,还是不要while了,时间会很长,直接跑100遍for循环,一直折半很快就可以把一个比较大的数变小,100次for足够把精度误差缩小
#include<cstdio>
#include<cmath>
#include<cstring>
#include<queue>
#include<algorithm>
using namespace std;
#define MAXN 6000
#define MAXM 1000000
#define INF 0x3f3f3f3f
int n,m,x,cnt;
int vis[MAXN],dis[MAXN],cur[MAXN],head[MAXN];
int u[MAXN],v[MAXN],cap[MAXN];
struct node
{
	int u,v,cap,flow,next;
}edge[MAXM];
void add(int a,int b,int c)
{
	node E={a,b,c,0,head[a]};
	edge[cnt]=E;
	head[a]=cnt++;
	node E1={b,a,0,0,head[b]};
	edge[cnt]=E1;
	head[b]=cnt++;
}
bool BFS(int s,int t)
{
	queue<int>q;
	memset(vis,0,sizeof(vis));
	memset(dis,-1,sizeof(dis));
	q.push(s);
	vis[s]=1;
	dis[s]=0;
	while(!q.empty())
	{
		int u=q.front();
		q.pop();
		for(int i=head[u];i!=-1;i=edge[i].next)
		{
			node E=edge[i];
			if(E.cap>E.flow&&!vis[E.v])
			{
				vis[E.v]=1;
				dis[E.v]=dis[E.u]+1;
				if(E.v==t) return true;
				q.push(E.v);
			}
		}
	}
	return false;
}
int DFS(int x,int a,int t)
{
	if(a==0||x==t) return a;
	int flow=0,f;
	for(int &i=cur[x];i!=-1;i=edge[i].next)
	{
		node &E=edge[i];
		if(dis[x]+1==dis[E.v]&&(f=DFS(E.v,min(E.cap-E.flow,a),t))>0)
		{
			a-=f;
			flow+=f;
			edge[i].flow+=f;
			edge[i^1].flow-=f;
			if(a==0) break;
		}
	}
	return flow;
}
int MAXflow(int s,int t)
{
	int flow=0;
	while(BFS(s,t))
	{
		memcpy(cur,head,sizeof(head));
		flow+=DFS(s,INF,t);
	}
	return flow;
}
bool judge(double mid)
{
	cnt=0;
	memset(head,-1,sizeof(head));
	for(int i=0;i<m;i++)
	add(u[i],v[i],(int)min(x*1.0,cap[i]*1.0/mid));
	return MAXflow(1,n)>=x;
}
int main()
{
	while(scanf("%d%d%d",&n,&m,&x)!=EOF)
	{
		
		memset(u,0,sizeof(u));
		memset(v,0,sizeof(v));
		memset(cap,0,sizeof(cap));
		for(int i=0;i<m;i++)
		scanf("%d%d%d",&u[i],&v[i],&cap[i]);
		double l=0,r=1e10,mid;
		double ans=0;
		for(int i=0;i<=100;i++)
		{
			mid=(l+r)/2;
			if(judge(mid))
			{
				ans=mid;
				l=mid;
			}
			else
			r=mid;
		}
		printf("%.10lf\n",ans*x);
	}
	return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值