AC这道题目不容易啊,看着蛮容易的,实则检测除了自己对最短路径算法的很多理解不到位之处。
第一:开始想这道题目的时候忽然对relaxing有了一种不熟悉的感觉,觉得relaxing对这道题目来说是不合适的,这道题目是求最大值,但是如果一个国家的汇率减去手续费变少了,后面一个国家就不会被更新了。我也不知道自己怎么想起来这个了。后来越想越不对,越想越觉得,这不是一道普通的求“最短路径”的问题,于是我奇葩的用变种的BFS来来做,这种做法,的确是我自己想出来的,想出来的时候还洋洋自得了。(其实是一个可以输出所有路径极其排列的算法....)但是跑样例的时候就是跑不对。后来一想,这种算法不会输出环,但是题中的答案是有环存在的,那么...这个题到底是什么妖怪?
就此卡住,然后回想,想了好久,终于忍不住去找结题报告,才发现,自己对松弛理解错了,更新的是后一个节点,后一个节点只和自己之前比较和前一个节点一点关系都没有,因此,如果有一条通往他的路径可以使原典到他的路径变短,他就会变短,因此,最短路径还是对的,而这道题目,也可以用最短路径的算法来做。
后来写BF算法的时候,又卡住了,最后终于想明白,是把边遍历N-1遍,是边而不是点,而且这个遍历不需要保存图的关系。另外,BF的出发点原点要 注意单独赋值,除了原点之外的都赋给无穷大(若求最大路径赋给无穷小),然后往小了松弛。
最后再松弛一遍边,那么就可以找到负环了(如果是找最大值就可以找到正环了)。
#include <iostream>
using namespace std;
struct c{
int s;
int e;
double r;
double m;
};
int main()
{
int n,m,s;
double dist[102];
double v;
int ts,te;
c* edge[202];
c* c1;
c* c2;
int i,j,k,en=0;
cin>>n>>m>>s>>v;
for(i=0;i<202;i++)
edge[i]=NULL;
for(i=0;i<102;i++)
dist[i]=0;
for(i=0;i<m;i++)
{
cin>>ts>>te;
c1=new c;
c1->s=ts;
c1->e=te;
cin>>c1->r>>c1->m;
edge[en]=c1;
en++;
c2=new c;
c2->s=te;
c2->e=ts;
cin>>c2->r>>c2->m;
edge[en]=c2;
en++;
}
dist[s]=v;
for(i=0;i<n-1;i++)
{
for(j=0;edge[j]!=NULL;j++)
{
c1=edge[j];
if(dist[c1->e]<(dist[c1->s]-c1->m)*c1->r)
dist[c1->e]=(dist[c1->s]-c1->m)*c1->r;
}
}
bool is=false;
for(i=0;edge[i]!=NULL;i++)
{
c1=edge[i];
if(dist[c1->e]<(dist[c1->s]-c1->m)*c1->r)
{
cout<<"YES";
is=true;
return 0;
}
}
if(!is)
{
cout<<"NO";
}
return 0;
}