0
点赞
收藏
分享

微信扫一扫

计蒜客——闯关游戏 SPFA找最长路

软件共享软件 2022-04-01 阅读 49
c++

思路:将生命值变化转换成边的权重,而结点1到自身,即dis[1] = 100,然后找单源最长路,注意若图中有正环,需要特殊处理,在代码中有给出

#include <bits/stdc++.h>

using namespace std;

const int INF = 10000000;
const int N = 105;
const int M = N*N+10;

struct edge{
    int v,w,next;
}edges[M];

int head[N];
int nums = 0;

void insert_list(int u,int v,int w){  //链表头插法
    edges[nums].v = v;
    edges[nums].w = w;
    edges[nums].next = head[u];
    head[u] = nums++;
}

queue<int> q;

bool vis[N];  //判断是否已经在队列中

int cnt[N];  //存储入队次数

int dis[N];  //源点到每个点的距离

int n;

//求最长路
bool SPFA(int u){
    memset(dis,-0x3f,sizeof dis);  //求最长路
    dis[u] = 100;
    q.push(u);
    vis[u] = true;
    cnt[u]++;
    while(!q.empty()){
        int curr_v = q.front();
        q.pop();
        vis[curr_v] = false;

        if(dis[n] == INF){  //若终点在正环上或者经过正环能到终点,即刻退出
            return true;
        }

        if(cnt[curr_v] >= n){  //若存在正环,此结点不再入队,否则会出现死循环
            vis[curr_v] = true;
        }

        for(int j = head[curr_v]; ~j; j = edges[j].next){
            int v = edges[j].v;
            int w = edges[j].w;
            if(dis[v] < dis[curr_v] + w){  //求最长路
                dis[v] = dis[curr_v] + w;
                if(!vis[v]){
                    q.push(v);
                    vis[v] = true;
                    cnt[v]++;
/*//当这个结点入队次数超过结点数n,说明存在正环,正环代表你可以一直在这刷生命值,
若从起点到终点经过这个环,则必能通关,让这个结点的生命值开到正无限即可*/
                    if(cnt[v] >= n)
                    {
                        dis[v] = INF;
                    }
                }
            }
        }
    }

    if(dis[n] > 0){
        return true;
    }
    else{
        return false;
    }

}


int main() {
    int m;
    cin>>n>>m;

    memset(head,-1,sizeof head);  //初始化头节点

    for(int i = 1; i <= m; ++i){
        int hp,rooms,to;
        cin>>rooms>>to>>hp;
        insert_list(rooms,to,hp);
    }

    if(SPFA(1)){
        cout<<"Yes"<<endl;
    }
    else{
        cout<<"No"<<endl;
    }

   return 0;
}
举报

相关推荐

0 条评论