导航

题意:

有n种钱币,m个钱币兑换点,小明一开始有第n种钱币数量为w。

每个兑换点可以将两种不同的钱币相互兑换,但是兑换前要先收取一定的费用,然后按照比例兑换。

问小明是否可以经过一系列的兑换之后能够将持有的第n种钱的数量增加。

这题大概就是看是否存在权值为正的环。如果存在这样的环,那么可以一直循环,然后在适当的时候兑换成第n种钱币。

这种算法一定要看好兑换率的范围!~

思路:

利用SPFA算法,当一个点松弛次数超过N次的时候我们认为存在一个正环。

#include<stdio.h>
#include<string.h>
#include<queue>
using namespace std;
int n,m,stc;
int ednum;
int cnt[105];
double stnum;
double dis[105];
bool vis[105];
struct edge
{
    int id;
    double cost,plu;
    edge *next;
};
edge edges[10005];
edge *adj[105];
inline void addEdge(int a,int b,double c,double d)
{
    edge *tmp;
    tmp=&edges[ednum];
    ednum++;
    tmp->id=b;
    tmp->cost=c;
    tmp->plu=d;
    tmp->next=adj[a];
    adj[a]=tmp;
}
bool SPFA()
{
    int id;
    memset(cnt,0,sizeof(cnt));
    memset(vis,0,sizeof(vis));
    for(int i=1;i<=n;i++)
    {
        dis[i]=-1;
    }
    dis[stc]=stnum;
    queue<int>q;
    q.push(stc);
    vis[stc]=1;
    cnt[stc]++;
    while(!q.empty())
    {
        id=q.front();
        q.pop();
        vis[id]=0;
        for(edge *p=adj[id];p;p=p->next)
        {
            if((dis[id]-p->cost>0)&&((dis[id]-p->cost)*p->plu>dis[p->id]))
            {
                cnt[p->id]++;
                if(cnt[p->id]>n)//如果松弛次数超过n次,则说明存在正环
                    return 1;
                dis[p->id]=(dis[id]-p->cost)*p->plu;
                if(!vis[p->id])
                {
                    q.push(p->id);
                    vis[p->id]=1;
                }
            }
        }
    }
    return 0;
}
int main()
{
    int a,b;
    double c,d,e,f;
    scanf("%d%d%d%lf",&n,&m,&stc,&stnum);
    for(int i=1;i<=m;i++)
    {
        scanf("%d%d%lf%lf%lf%lf",&a,&b,&d,&c,&f,&e);
        addEdge(a,b,c,d);
        addEdge(b,a,e,f);
    }
    if(SPFA())
        printf("YES\n");
    else
        printf("NO\n");
    return 0;
}