LightOJ - 1404 Sending Secret Messages 费用流 EK算法

Alice wants to send Bob some confidential messages. But their internet connection is not secured enough. As their names have been used in many networking schemes, they are very rich now. So, they don't want to send encoded messages, they want to use secured dedicated connection for them. So, they talked to some ISPS (Internet Service Providers) about their problem. Only they get is that there are N routers in the network, some of them share bidirectional links. Each link has a capacity, and for each KB of data passing through this link, they have to pay some money. Assume that Alice is connected with the 1st router and Bob is connected to the Nth router.

For example, in the picture, Alice wants to send 4 KB data from router 1 to router 6. Each link is identified by two integers in the form (a, b) where 'a' denotes the capacity of the link and 'b'denotes per KB cost of the link. So, Alice can send 1KB of data through 1 - 2 - 3 - 4 - 6 (cost 8), 2KB data through 1 - 5 - 6 (cost 2 * 9=18) and 1KB data through 1 - 3 - 4 - 6 (cost 11). So, the total cost is 37 units.

Now Alice wants to send P KB of data to Bob. You have to find the minimum amount of money they have to pay to achieve their goal.

Input

Input starts with an integer T (≤ 50), denoting the number of test cases.

Each case starts with a blank line. Next line contains three integers N (2 ≤ N ≤ 50)M (0 ≤ M ≤ N*(N-1)/2) and P (1 ≤ P ≤ 1000), where M denotes the number of bidirectional links. Each of the next M lines contains four integers u v w c (1 ≤ u, v ≤ N, u ≠ v, 1 ≤ w, c ≤ 100), meaning that there is a link between router u and v, and at most c KB data can be sent through this link, and each KB of data through this link will cost w. You can assume that there will be at most one connection between a pair of routers.

Output

For each case, print the case number and the minimum amount of money required or "impossible" if it's not possible to send P KB of data.

Sample Input

3

 

6 9 4

3 1 9 8

1 2 1 2

1 5 6 1

5 6 2 8

6 4 2 2

4 2 7 6

2 6 7 9

3 4 5 1

3 2 2 3

 

6 9 9

3 1 9 8

1 2 1 2

1 5 6 1

5 6 2 8

6 4 2 2

4 2 7 6

2 6 7 9

3 4 5 1

3 2 2 3

 

4 4 20

1 3 1 3

3 4 1 4

1 2 1 2

2 4 1 5

Sample Output

Case 1: 37

Case 2: 139

Case 3: impossible

题意:给定一个图,有n个顶点m条无向边,每条边都有容量和费用,求从1到n穿输p的数据量时的费用。题中流量和费用给反了

题解:费用流模板题  EK算法介绍:点击查看

#include<iostream>
#include<cstdio>
#include<cstring>
#include<queue> 
using namespace std;
#define INF 0x3f3f3f3f
const int N=52;
struct node{
	int st,to,nex,cost,cap;
}e[N*N*2];
int head[N],dis[N],vis[N],pre[N],len;
int n,m,p; 
void Init()
{
	len=0;
	memset(head,-1,sizeof(head));
}
void Add(int u,int v,int cost,int cap)
{
	e[len].st=u;
	e[len].to=v;
	e[len].cost=cost;
	e[len].cap=cap;
	e[len].nex=head[u];
	head[u]=len++;
	
	e[len].st=v;
	e[len].to=u;
	e[len].cost=-cost;
	e[len].cap=0;
	e[len].nex=head[v];
	head[v]=len++;
}
int cost_flow(int s,int t,int p)
{
	int ans=0;
	while(p>0)
	{
		memset(dis,INF,sizeof(dis));
		memset(vis,0,sizeof(vis));
		memset(pre,-1,sizeof(pre));
		queue<int> q;
		dis[s]=0;
		vis[s]=1;
		q.push(s);
		while(!q.empty())
		{
			int now=q.front();q.pop();
			vis[now]=0;
			for(int i=head[now];i!=-1;i=e[i].nex)
			{
				int to=e[i].to;
				if(e[i].cap>0&&dis[to]>dis[now]+e[i].cost)
				{
					dis[to]=dis[now]+e[i].cost;
					pre[to]=i;
					if(!vis[to])
					q.push(to),vis[to]=1;
				}
			}
		}
		if(dis[t]==INF) return -1;
		int minn=p;
		for(int i=pre[t];i!=-1;i=pre[e[i].st])
			minn=min(minn,e[i].cap);
		for(int i=pre[t];i!=-1;i=pre[e[i].st])
			e[i].cap-=minn,e[i^1].cap+=minn;
		ans+=minn*dis[t];
		p-=minn;
	}
	return ans;
}
int main()
{
	int T,x,y,z,w,cas=1;
	scanf("%d",&T);
	while(T--)
	{
		Init();
		scanf("%d%d%d",&n,&m,&p);
		for(int i=1;i<=m;i++)
		{
			scanf("%d%d%d%d",&x,&y,&z,&w);
			Add(x,y,w,z);
			Add(y,x,w,z);
		}
		int ans=cost_flow(1,n,p);
		printf("Case %d: ",cas++);
		if(ans!=-1) printf("%d\n",ans);
		else printf("impossible\n");
	}
	return 0;
} 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值