HDU - 1317 (XYZZY) 最长路 spfa

题目:

HDU - 1317

题意:

要求从 1 开始一直走到 n 否可以到达,开始时你在 1 处你拥有100能量,你可以走到这房间所连接的任何房间,你去了之后你的能量值会加上那个房间的能量值(有正有负)所以就会造成两种结果,如果你的能量值小于等于0,表示你将死亡,否则你还可以继续走,最后就问你可以到达 n 号房间吗?

思路:

我们利用最短路(最长路)最基本的思想 —— 贪心 来考虑这个问题,我们要想到达那个点,我们其实心里想的是怎么可以让我到达那个点的时候我的能量是最多的那种情况。
所以这就是一个简单的最长路,每次只要到达这个点的能量值可以更新(变得更大)就更新就可以了,最后我们要看的就是否可以到达n点处。
是否到达可以分为两种情况:
① 无正环:
在没有正环的情况下,最长路跑得到就是到, 跑不到就是到不了。
② 有正环:
有正环的时候你就要判断正环内的一个点是否可以到达n, (为什么是正环的一个点是否可以到n这个建议自己想一下, 其实也很简单你这个正环就是从 1 开始跑得到的,所以 1 可以到正环 正环可以到 n 。1 就可以到 n) 在有正环的时候我刚开始是直接判断 1 是否可以到 n 就WA了。其实, 这也不难想,正环的目的就是使的我的能量值无限大,但是,你直接判断 1 是否可以到 n 他选择的那条路不一定含正环点。所以就错了。

AC CODE

#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
using namespace std;
typedef long long LL;
const int maxn= 110;
const int M = 7e4 + 10;
const int inf = 0x3f3f3f3f;
const LL INF = 9223372036854775807;
const double efs = 1e-9;
const int mod = 1000000007;
int vis[maxn];
int vis1[maxn];
int dis[maxn];
int head[maxn];
int visited[maxn];
int energy[maxn];
int cnt;
struct edge {
    int v, w, next;
}e[maxn * maxn];
struct node {
    int u;
    int dist;
    friend bool operator < (node a, node b) {
        return a.dist > b.dist;
    }
};
void add_edge (int uu, int vv, int ww) {
    e[cnt].v =vv, e[cnt].w = ww; e[cnt].next = head[uu];
    head[uu] = cnt++;
}
vector <int> vt[maxn];

int spfa(int x, int n) {
    vis[x] = 1;
    dis[x] = 100;
    queue <int> q;
    q.push(x);
    while(!q.empty()) {
        int now = q.front();
        q.pop();
        vis[now] = 0;
        visited[now]++;
        if(visited[now] > n) return -1;
        if(now == n) return 1;
        for(int i = head[now]; i != -1; i = e[i].next) {
            int temp = e[i].v;
            if(dis[temp] < dis[now] + e[i].w) {
                dis[temp] = dis[now] + e[i].w;
                if(!vis[temp]) {
                    vis[temp] = 1;
                    q.push(temp);
                }
            }
        }
    }
    return 0;
}

int bfs(int x, int n) {
    memset(vis1, 0, sizeof(vis1));
    vis1[x] = 1;
    queue <int> q;
    q.push(x);
    while(!q.empty()) {
        int now = q.front();
        q.pop();
        if(now == n) return 1;
        for(int i = head[now]; i != -1; i = e[i].next) {
            if(!vis1[e[i].v]) {
                q.push(e[i].v);
                vis1[e[i].v] = 1;
            }
        }
    }
    return 0;
}

int main()
{
    int n;
    while(scanf("%d", &n) && n != -1) {
        memset(head, -1, sizeof(head));
        memset(vis, 0, sizeof(vis));
        memset(dis, 0, sizeof(dis));
        memset(visited, 0, sizeof(visited));
        cnt = 0;
        for(int i = 1; i <= n; i++) {
            vt[i].clear();
            int tmp;
            scanf("%d %d", &energy[i], &tmp);
            for(int j = 0; j < tmp; j++) {
                int k;
                scanf("%d", &k);
                vt[i].push_back(k);
            }
        }
        for(int i = 1; i <= n; i++) {
            for(int j = 0; j < vt[i].size(); j++) {
                add_edge(i, vt[i][j], energy[vt[i][j]]);
            }
        }
        int ans = spfa(1, n);
        //cout << ans << " " << dis[n] << endl;

        if(ans == -1) {
            int xx;
            for(int i = 1; i <= n; i++) {
                if(visited[i] > n) {
                    xx = i;
                    break;
                }
            }
            int flag = bfs(xx, n);
            if(flag) printf("winnable\n");
            else printf("hopeless\n");
        }
        else if(ans == 0)printf("hopeless\n");
        else printf("winnable\n");
    }
    return 0;
}

仔细理解看代码,如有错,望指出。

你可能感兴趣的:(最短路)