POJ - 1860 最短路 SPFA 判断正环 模版 写了很久

题目

在这里插入图片描述

题解思路

题目不容易理解,用迪杰斯特拉好像不行,这里好像用源点出发容易理解点,用邻接表存图 (一开始佣金汇率输入反了 痛苦啊 )。
因为每一步的有的钱兑换出来的钱是不一样的可能亏可能赚,所以最好就以源点出发来进行对钱的兑换,从存入dis数组。
当一个dis的值被松弛的次数比 N还多时(在某个地方被多次松弛) 就存在正环 ! 就是不断加钱,刷钱的感觉。此时return即可!
SPFA
对每个点都可能多次入队 ,当可以松弛时,被松弛的点可能又入队,就可以多次松弛,这样就可以判断正环和负环!最短路也是行的,当所有路都是最短路时,没有点能再入队了,不断出队!

AC代码

#include <iostream>
#include <cstdio>
#include <vector>
#include <cstring>
#include <queue>
using namespace std;
#define INF 20000.0
struct bian
{
    int z;
    double h,y;
};
vector <bian> head[105];
bool vis [105];
int cnt[105];
double dis[105];
int main ()
{
    int n,m,s;
    bian tmm;
    double sum;
    cin>>n>>m>>s>>sum;
    for (int i = 1 ;i <= m ;i++ )
    {
        int a,b;
        double y,h;
        cin>>a>>b>>h>>y;
        tmm.z = b;
        tmm.y = y;
        tmm.h = h;
        head[a].push_back(tmm);
        cin>>h>>y;
        tmm.z = a;
        tmm.y = y;
        tmm.h = h;
        head[b].push_back(tmm);
    }
   /* for (int i = 1 ;i <= n ;i++ )
    {
            for (int k = 0 ;k<head[i].size() ; k++ )
        {
            printf("%d,%d,%f,%f   ",i,head[i][k].z,head[i][k].y,head[i][k].h );
        }
        printf("\n");
    } */
    memset(vis, 0 ,sizeof(vis) );
    memset(dis, 0 , sizeof(dis));
    memset(cnt , 0 , sizeof(cnt) );
    queue <int> q;
    q.push(s);
    dis[s] = sum ;
    cnt[s]++;
    double tmp;
    vis[s] = 1 ;
    while(!q.empty())
    {
        int t = q.front();
        q.pop();
	//	printf("出队的点是:%d\n",t);
        vis[t] = 0 ;
        for (int i= 0 ; i<head[t].size() ; i++ )
        {
            tmp  =  (dis[t] - head[t][i].y)*head[t][i].h ;
            if (dis[head[t][i].z] < tmp  )
            {
                dis[head[t][i].z] =  tmp ;
                cnt[head[t][i].z]++ ;
                if (cnt[head[t][i].z]>= n )
                {
                    cout<<"YES\n";
                    return 0;
                }
               if ( vis[head[t][i].z] == 0  )
               {
                   vis[head[t][i].z] = 1;
                   q.push(head[t][i].z);
               }
            }
        }
     /*   for (int i = 1 ;i <= n ; i++ )
           printf("dis[%d]=%f  ",i,dis[i]);
        printf("\n"); */
    }
    cout<<"NO\n";
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值