POJ 1860 Currency Exchange 【spfa判断正环】
原题链接:传送门
题目大意:
给出几种货币以及它们正向反向兑换的汇率和手续费,
求给定一种货币以及金额,问能否经过若干次货币兑换后回到原给定的货币种类,
若能实现金额数增加则输入YES,否则输出NO
具体思路:
最短路变形,spfa求解,若换到某种货币金额数大于该种货币原有金额则更新,若发现某条边更新了超过n次,说明存在正环,能赚到钱(即走一次环换成该种货币赚一点点,当走多次环,积少成多,总会出现赚的钱大于换回原有货币所需的佣金)
因此可根据图中是否存在正环判断能否赚到钱
具体代码:
#include<iostream>
#include<cstdio>
#include<stdlib.h>
#include<queue>
#include<vector>
#include<algorithm>
using namespace std;
const int N = 105;
struct Node {
int x, y;
double r, c;
Node(int x, int y, double r, double c)
{
this->x = x, this->y = y;
this->r = r, this->c = c;
}
};
vector<Node> maps[N]; //用stl来存图
int visit[N]; //记录是否在队列中
int index[N]; //记录入队次数
double d[N]; //d[i]表示一开始的钱换成i种货币时,i种货币能环到的数额
int n, m, kind;
double money;
int flag = 0;
void spfa()
{
for (int i = 1; i <= n; i++)
visit[i] = 0, index[i] = 0, d[i] = 0;
d[kind] = money; //初始化原有货币种类的数额
visit[kind] = 1;
index[kind] = 1;
queue<int> q;
q.push(kind);
while (q.size())
{
int t = q.front();
q.pop();
visit[t] = 0;
for (vector<Node>::iterator it = maps[t].begin(); it != maps[t].end(); it++)
{
double get = (d[t] - it->c)*it->r;
if (d[it->y] < get) { //若换成该货币,该种货币的金额数有增加
d[it->y] = get;
if(visit[it->y])continue;
visit[it->y] = 1;
q.push(it->y);
index[it->y]++;
if (index[it->y] > n) { //有正环
flag = 1;
return;
}
}
}
}
}
int main()
{
cin >> n >> m >> kind >> money;
for (int i = 1; i <= m; i++)
{
int x, y;
double r1, c1, r2, c2;
cin >> x >> y >> r1 >> c1 >> r2 >> c2;
maps[x].push_back(Node(x, y, r1, c1));
maps[y].push_back(Node(y, x, r2, c2));
}
spfa();
if(flag)printf("YES\n");
else printf("NO\n");
return 0;
}