UVA - 10594 Data Flow 最小费用最大流

题目大意:有N个点,每个点的容量都是相同的,都为K,给出M个连接的点和这两个连接的点通信的代价,求将D个数据从点1送到点N的最小代价是多少

解题思路:每个点的容量可以将其看成是边的容量,然后设置一个超级源点0,超级源点0和点1相连,点0和点1之间的权值为D,这样图就建成了,注意两个点之间传输的代价是有可能大于10^15,所以要用long long

#include<cstdio>
#include<cstring>
#include<queue>
#define maxn 110
#define maxm 21000
#define ll long long
const ll INF = 1000000000000000000ll;
using namespace std;
int a[maxm],b[maxm],vis[maxn],u[maxm],v[maxm],head[maxm],next[maxm],line[maxm],pre[maxm];
int e,N,M;
ll t[maxm],flow[maxm],cost[maxm],d[maxm],D,K;
void add(int x,int y,ll c,ll f) {

	u[e] = x;
	v[e] = y;
	cost[e] = c;
	flow[e] = f;
	next[e] = head[x];
	head[x] = e;
	e++;

}

void init() {

	e = 0;
	memset(head,-1,sizeof(head));
	for(int i = 0; i < M; i++) 
		scanf("%d%d%lld",&a[i],&b[i],&t[i]);	
	
	scanf("%lld%lld",&D,&K);

	for(int i = 0; i < M; i++) {
		add(a[i],b[i],t[i],K);
		add(b[i],a[i],-t[i],0);
		add(b[i],a[i],t[i],K);
		add(a[i],b[i],-t[i],0);	
	}

	add(0,1,0,D);
	add(1,0,0,0);

}

void spfa() {

	int u;	
	memset(vis,0,sizeof(vis));
	queue<int> q;

	for(int i = 1; i <= N; i++)
		d[i] = INF;

	d[0] = 0;
	q.push(0);	

	while(!q.empty()) {
		u = q.front();
		vis[u] = 0;
		q.pop();	
		for(int i = head[u]; i != -1; i = next[i]) 
			if(flow[i] && d[v[i]] > d[u] + cost[i]) {
				d[v[i]] = d[u] + cost[i];
				pre[v[i]] = u; 
				line[v[i]] = i;	
				if(!vis[v[i]]) {
					vis[v[i]] = 1;
					q.push(v[i]);	
				}
			}	
	}
}

void EK() {
	long long ans = 0, f = 0;
	while(1) {
		spfa();
		if(d[N] == INF)
			break;
		ll MIN = INF;
		int temp;
		for(int i = N; i != 0; i = pre[i]) {
			temp = line[i];
			if(flow[temp] < MIN)
				MIN = flow[temp];
		}
		for(int i = N; i != 0; i = pre[i]) {
			int temp = line[i]; 
			flow[temp] -= MIN;
			flow[temp^1] += MIN;
		}
		ans += MIN * d[N];
		f += MIN;
	}
	if(f == D)
		printf("%lld\n",ans);
	else
		printf("Impossible.\n");

}

int main() {
	while(scanf("%d%d",&N,&M) != EOF) {
		init();		
		EK();
	}	
	return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值