poj1860(最短路,负环)

/*
translation:
	给出若干货币,以及货币之间的转换方法。假设知道A->B:r=29.75,c=0.39。则由100货币A转换为B为
	B=(100 - 0.39) * 29.75 。现在给你一种特定的货币以及每种货币间的r和c,求其能否通过某种转换方式
	使得最终转换为本来货币时,资产增加?
	
solution:
	最短路径的bellmanFord算法,判断负环。
	可以设dis[i]为转换到i货币时的最大资产,则本质上就是一个最长路径。这样一来跟求单源最短路径其实
	也没什么区别。题目问能否使得资产增加,这就可以联想到在最短路径中求负环的问题,普通单源最短路径中的
	负环使得在经过该环时回到源点的路径更短。而对应到此题也是同样的道理,就是求是否存在一个环使得兑换到
	原货币时资产增加。如此利用bellmanFord算法就可以轻松解出来。
	
note:
date:
	2016.8.21
*/
#include <iostream>
#include <cstdio>
#include <vector>
#include <cstring>
#include <queue>

using namespace std;
const int maxn = 101;
const int INF = 1 << 30;

struct Edge {
	int from, to;
	double r, c;
	Edge(int f, int t, double r, double c) : from(f), to(t), r(r), c(c) {}
	Edge() {}
};
vector<Edge> edges;
vector<int> G[maxn];
int n, m, s, cnt[maxn];
double dis[maxn], v;	//到了i点的资金数量
bool inq[maxn];

void addEdge(int from, int to, double r1, double c1, double r2, double c2) {
	edges.push_back(Edge(from, to, r1, c1));
	edges.push_back(Edge(to, from, r2, c2));
	int len = edges.size();
	G[from].push_back(len-2);
	G[to].push_back(len-1);
}

bool bellmanFord(int s) {
	queue<int> q;
	memset(inq, 0, sizeof(inq));
	memset(cnt, 0, sizeof(cnt));
	for(int i = 1; i <= n; i++)    dis[i] = -INF;
	dis[s] = v;
	inq[s] = true;
	q.push(s);

	while(!q.empty()) {
		int u = q.front();	q.pop();
		inq[u] = false;
		for(int i = 0; i < G[u].size(); i++) {
			Edge& e = edges[G[u][i]];
			if(dis[u] > -INF && dis[e.to] < (dis[u] - e.c) * e.r) {
				dis[e.to] = (dis[u] - e.c) * e.r;
				if(!inq[e.to]) {
					q.push(e.to);
					inq[e.to] = true;
					if(++cnt[e.to] > n)	return false;
				}
			}
		}
	}
	return true;
}

int main()
{
	//freopen("in.txt", "r", stdin);
    while(~scanf("%d%d%d%lf", &n, &m, &s, &v)) {
		edges.clear();
		for(int i = 0; i < maxn; i++)	G[i].clear();

		int from, to;
		double r1, c1, r2, c2;
		for(int i = 0; i < m; i++) {
			scanf("%d%d%lf%lf%lf%lf", &from, &to, &r1, &c1, &r2, &c2);
			addEdge(from, to, r1, c1, r2, c2);
		}

		if(!bellmanFord(s))	printf("YES\n");
		else				printf("NO\n");
    }
    return 0;
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值