大部分题解都是Bellmean_Ford和SPFA,最近在练Dijkstra的板,就放在这道题上写一写叭。
题意
给定n种货币,且存在m种交易方式,对于每一种交易方式,有税率与佣金等参数。例如现存在一种交易方式:从货币A到货币B,原有货币A的数量为Sa,税率为rate,佣金为dec,则可得货币B的数量为Sb=(Sa-dec)*rate。问经过交易能否使原有货币价格升高。
分析
由于允许的货币交易次数是无限的,故不能将视野局限于某几次交易能否使手中资本得到升高,而是去判断是否存在一种交易圈能够使得手中的资金不断升高。
对于这些货币以及货币间的交易方式,可以抽象成图的节点和边,每一条边连接两个节点,且存在税率与佣金等参数。那么要寻找到能使手中资金不断升高的交易圈,即在当前图中找到一个最大正环。这个概念其实是就和学习最短路算法时所提到的负圈判断一模一样,即在完成目前可进行的松弛操作(本题中是找到更长路)后,仍存在一些边(交易方式),使得手中资金仍然能够产生更大的价值。
解题过程
存图
采用邻接表存图(真的感觉邻接表好好用,但是这一题数据量小到用邻接矩阵就可以存下?)注意本题实际上是给出一个有向图。
优先队列+Dijkstra
定义节点结构体,记录节点编号以及当前节点下能获得的最大货币价值,重载运算符使得优先队列优先弹出当前最大价值节点。(题板,不做赘述)
检查正环
检查所有边,若存在一条边使得经过这条边的交易方式后货币价值仍能够提高,则返回真,输出YES,反之即输出NO。
AC代码
#include <iostream>
#include <stdio.h>
#include <string.h>
#include <stack>
#include <queue>
#include <map>
#include <set>
#include <vector>
#include <math.h>
#include <bitset>
#include <algorithm>
#include <climits>
#define IOS ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
using namespace std;
typedef long long int ll;
const int INF=0x3f3f3f3f;
const int N=500;
struct edge {
int u,v;
double rate,dec;
edge(int a,int b,double c,double d) {
u=a;v=b;rate=c;dec=d;
}
};
vector<edge> G[N];//邻接表存图
struct s_node {
int id;
double val;
s_node(int a,double b) {
id=a;val=b;
}
//重载运算符
bool operator<(const s_node &a) const {
return val<a.val;
}
};
int n,m,s;
double V;
bool dijkstra() {
double dis[N];//记录所有点到起点能够产生的最大价值
bool vis[N];
for(int i=1;i<=n;i++) {
//与最短路相反,初始化定义为0,即当前无价值
dis[i]=0;
vis[i]=false;
}
//对于起点,本存在有价值V
dis[s]=V;
priority_queue<s_node> q;
q.push(s_node(s,dis[s]));
while(!q.empty()) {
//优先弹出目前已产生价值中有最大价值的节点
s_node u=q.top();
q.pop();
if(vis[u.id]) continue;
vis[u.id]=true;
//检查从该节点出发的所有交易方式
for(int i=0;i<G[u.id].size();i++) {
//交易方式y
edge y=G[u.id][i];
if(vis[y.v]) continue;
//通过y的交易之后若得到更大价值,则拓展新邻居
if(dis[y.v]<(u.val-y.dec)*y.rate) {
dis[y.v]=(u.val-y.dec)*y.rate;
q.push(s_node(y.v,dis[y.v]));
}
}
}
//非常暴力地查每一条边,但应该只是看起来暴力,毕竟边数不变。
for(int i=1;i<=n;i++) {
for(int j=0;j<G[i].size();j++) {
edge x=G[i][j];
//若仍存在一种交易方式x,能够扩大价值,则返回true.
if((dis[x.u]-x.dec)*x.rate>dis[x.v]) return true;
}
}
return false;
}
void solve() {
cin>>n>>m>>s>>V;
for(int i=1;i<=m;i++) {
int u,v;cin>>u>>v;
double x,y;cin>>x>>y;
G[u].push_back(edge(u,v,x,y));
cin>>x>>y;
G[v].push_back(edge(v,u,x,y));
}
if(dijkstra()) {
cout<<"YES"<<endl;
} else {
cout<<"NO"<<endl;
}
}
int main()
{
//#define mytest
#ifdef mytest
freopen("test.in","r",stdin);
freopen("test.out","w",stdout);
#endif
solve();
return 0;
}