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;
}