题目大意:
输入n,m,s,v分别表示货币种类数量,货币交换所的数量,某人所拥有的货币编号以及该货币该人拥有的单位数量,每个交换所只能在两种货币之间相互兑换,输入m个交换所的情况,每一行用a,b,r,c,r1,c1,分别表示a到b的汇率和手续费以及b到a的货币和手续费,例如从a兑换到b:value b = (value a-c)*r;问你是否可以通过交换是的最后再换到该人最开始拥有的货币种类时,该人所拥有的货币数量增加;
基本思路:
首先从这个题怎么联系到最短路,首先,没想到什么算法,然后有没想到什么直接的解法,很自然的想到最短路,为啥会想到最短路呢?
首先货币之间的各种兑换可以类比一下最短路的松弛,到这,也只是猜测,然后因为要再交换会最开始的货币 ,所以必须要有回路,用最短路的话松弛操作在货币交换第一次回到最开始货币的过程中并没有意义,因为这时候是第一次换到某种货币,所以没有松弛,那么一开始要把该种货币的货币数量初始化为零才行,因为有回路,所以会第二次第三次第n次到达该点这时候松弛就有了意义,看是不是能换成这种货币更多,如果可以的话就说明最开始的货币在交换过程中货币数量增加了,那么,就满足题目中的条件,但是下一个问题马上出现了,怎么跳出呢,就加一个用来计数的数组就ok了,反之第二次回到最开始货币时如果货币数量没有变多,那么必然无法满足题目中的条件,自然可以进行完,不会无限进行入队出队操作,这时候直接返回false就好;
再用spfa做题时一定要记住,满足条件的后续点进队啊(当时傻了,忘了进队操作),一定要把是否在队列中的标记改回来(勿忘);同时这个题告诉我们,spfa只要再加一个数组就可能判断是是否存在回路!!!spfa做题时记住几点:vis数组,addedge模板,初始化;
代码如下:
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<queue>
using namespace std;
const int maxn = 100+10;
int vis[maxn],head[maxn],cnt[maxn];
struct Edge
{
int to;
double r,c;
int next;
};
Edge edge[maxn*2];
int pos,n,m,s;
double d[maxn];
double v;
void addedge(int a,int b,double r,double c)
{
edge[pos].to=b;
edge[pos].r=r;
edge[pos].c=c;
edge[pos].next=head[a];
head[a]=pos++;
}//模板记住,充分理解;
bool spfa()
{
memset(vis,0,sizeof(vis));
memset(d,0,sizeof(0));
memset(cnt,0,sizeof(cnt));
queue<int>q;
while(!q.empty()) q.pop();
q.push(s);vis[s]=1;d[s]=v;cnt[s]++;//一开始对起始点进行的操作勿忘,尤其是d[s]这个;
while(!q.empty())
{
int t=q.front();q.pop();vis[t]=0;//别忘了改回来;
for(int i=head[t];i!=-1;i=edge[i].next)
{
int k=edge[i].to;
double r=edge[i].r;
double c=edge[i].c;
if(d[k]<(d[t]-c)*r)
{
d[k]=(d[t]-c)*r;
if(!vis[k])
{
vis[k]=1;
cnt[k]++;
q.push(k);//勿忘;
}
if(cnt[k]>n) return true;
}
}
}
return false;
}
int main()
{
scanf("%d%d%d%lf",&n,&m,&s,&v);
pos=0;//勿忘;
memset(head,-1,sizeof(head));
int a,b;
double r,c;
for(int i=0;i<m;i++)
{
scanf("%d%d%lf%lf",&a,&b,&r,&c);
addedge(a,b,r,c);
scanf("%lf%lf",&r,&c);
addedge(b,a,r,c);
}
if(spfa()) printf("YES\n");
else printf("NO\n");
return 0;
}
#include<cstring>
#include<cmath>
#include<algorithm>
#include<queue>
using namespace std;
const int maxn = 100+10;
int vis[maxn],head[maxn],cnt[maxn];
struct Edge
{
int to;
double r,c;
int next;
};
Edge edge[maxn*2];
int pos,n,m,s;
double d[maxn];
double v;
void addedge(int a,int b,double r,double c)
{
edge[pos].to=b;
edge[pos].r=r;
edge[pos].c=c;
edge[pos].next=head[a];
head[a]=pos++;
}//模板记住,充分理解;
bool spfa()
{
memset(vis,0,sizeof(vis));
memset(d,0,sizeof(0));
memset(cnt,0,sizeof(cnt));
queue<int>q;
while(!q.empty()) q.pop();
q.push(s);vis[s]=1;d[s]=v;cnt[s]++;//一开始对起始点进行的操作勿忘,尤其是d[s]这个;
while(!q.empty())
{
int t=q.front();q.pop();vis[t]=0;//别忘了改回来;
for(int i=head[t];i!=-1;i=edge[i].next)
{
int k=edge[i].to;
double r=edge[i].r;
double c=edge[i].c;
if(d[k]<(d[t]-c)*r)
{
d[k]=(d[t]-c)*r;
if(!vis[k])
{
vis[k]=1;
cnt[k]++;
q.push(k);//勿忘;
}
if(cnt[k]>n) return true;
}
}
}
return false;
}
int main()
{
scanf("%d%d%d%lf",&n,&m,&s,&v);
pos=0;//勿忘;
memset(head,-1,sizeof(head));
int a,b;
double r,c;
for(int i=0;i<m;i++)
{
scanf("%d%d%lf%lf",&a,&b,&r,&c);
addedge(a,b,r,c);
scanf("%lf%lf",&r,&c);
addedge(b,a,r,c);
}
if(spfa()) printf("YES\n");
else printf("NO\n");
return 0;
}