[hdu1317]spfa

题意:给一个有向图,每个点有一个权值,从1个点出发,初始能量有100,每到达新的点,能量就会加上那个点的权值,当能量大于0时才能继续走,可以多次进入同一点。问能否到达目标点

思路:如果没正权环,则直接优先队列bfs模拟走的过程即可,因为先到不会比后到的能量少,那过程其实就和dijkstra差不多,但根据题目的意思,是可能存在正权环的,所以dijkstra行不通,于是考虑spfa。一旦某个点入队了n次,就可判定这个点在正权环上,通过在正权环上不断走来获得无限的能量,于是将这个点的能量值设为无穷大,并让它再入队一次后丢弃这个点(因为能量值变为了无穷大,需要用它来更新邻点,更新完了它就没有存在的意义了),同时判断这个点是否与目标点连通,如果连通,那么毫无疑问,目标点肯定可以顺利到达。


1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

69

70

71

72

73

74

75

76

77

78

79

80

81

82

83

84

85

86

87

88

89

90

91

92

93

94

95

96

97

98

99

100

101

102

103

104

105

106

107

108

109

110

111

112

113

114

115

116

117

118

119

120

121

122

123

124

125

126

127

128

129

130

131

132

133

134

135

#include <map>

#include <set>

#include <cmath>

#include <ctime>

#include <deque>

#include <queue>

#include <vector>

#include <cstdio>

#include <string>

#include <cstdlib>

#include <cstring>

#include <iostream>

#include <algorithm>

using namespace std;

#define X                   first

#define Y                   second

#define pb                  push_back

#define mp                  make_pair

#define all(a)              (a).begin(), (a).end()

#define fillchar(a, x)      memset(a, x, sizeof(a))

typedef long long ll;

typedef pair<intint> pii;

typedef unsigned long long ull;

#ifndef ONLINE_JUDGE

void RI(vector<int>&a,int n){a.resize(n);for(int i=0;i<n;i++)scanf("%d",&a[i]);}

void RI(){}void RI(int&X){scanf("%d",&X);}template<typename...R>

void RI(int&f,R&...r){RI(f);RI(r...);}void RI(int*p,int*q){int d=p<q?1:-1;

while(p!=q){scanf("%d",p);p+=d;}}void print(){cout<<endl;}template<typename T>

void print(const T t){cout<<t<<endl;}template<typename F,typename...R>

void print(const F f,const R...r){cout<<f<<", ";print(r...);}template<typename T>

void print(T*p, T*q){int d=p<q?1:-1;while(p!=q){cout<<*p<<", ";p+=d;}cout<<endl;}

#endif

template<typename T>bool umax(T&a, const T&b){return b<=a?false:(a=b,true);}

template<typename T>bool umin(T&a, const T&b){return b>=a?false:(a=b,true);}

template<typename T>

void V2A(T a[],const vector<T>&b){for(int i=0;i<b.size();i++)a[i]=b[i];}

template<typename T>

void A2V(vector<T>&a,const T b[]){for(int i=0;i<a.size();i++)a[i]=b[i];}

const double PI = acos(-1.0);

const int INF = 1e9 + 7;

/* -------------------------------------------------------------------------------- */

const int maxn = 107;

struct Graph {

    vector<vector<int> > G;

    void clear() { G.clear(); }

    void resize(int n) { G.resize(n + 2); }

    void add(int u, int v) { G[u].push_back(v); }

    vector<int> & operator [] (int u) { return G[u]; }

};

Graph G;

bool vis[maxn], flag[maxn];

int n;

int cnt[maxn], d[maxn], p[maxn];

bool dfs(int s, int t) {

    if (s == t) return true;

    vis[s] = true;

    for (int i = 0; i < G[s].size(); i ++) {

        int v = G[s][i];

        if (!vis[v]) if (dfs(v, t)) return true;

    }

    return false;

}

bool relax(int u, int v) {

    if (d[u] + p[v] > d[v]) {

        d[v] = d[u] + p[v];

        return true;

    }

    return false;

}

bool work() {

    queue<int> Q;

    Q.push(1);

    fillchar(d, 0);

    fillchar(flag, 0);

    fillchar(cnt, 0);

    d[1] = 100;

    flag[1] = true;

    while (!Q.empty()) {

        int u = Q.front(); Q.pop();

        flag[u] = false;

        if (u == n) return true;

        if (d[u] >= 1e8) {

            fillchar(vis, 0);

            if (dfs(u, n)) return true;

        }

        int sz = G[u].size();

        for (int i = 0; i < sz; i ++) {

            int v = G[u][i];

            if (relax(u, v)) {

                if (!flag[v]) {

                    flag[v] = true;

                    if (cnt[v] > n) continue;

                    if (cnt[v] == n) d[v] = INF;

                    Q.push(v);

                    cnt[v] ++;

                }

            }

        }

    }

    return false;

}

int main() {

#ifndef ONLINE_JUDGE

    freopen("in.txt""r", stdin);

    //freopen("out.txt", "w", stdout);

#endif // ONLINE_JUDGE

    int m, v;

    while (cin >> n, ~n) {

        G.clear();

        G.resize(n);

        for (int i = 1; i <= n; i ++) {

            scanf("%d%d", p + i, &m);

            for (int j = 0; j < m; j ++) {

                scanf("%d", &v);

                G.add(i, v);

            }

        }

        fillchar(vis, 0);

        if (!dfs(1, n)) puts("hopeless");

        else puts(work()? "winnable" "hopeless");

    }

    return 0;

}

时间: 2024-12-31 03:27:47

[hdu1317]spfa的相关文章

hdu1317(spfa判断正环+Floyd判断联通)

题意很好理解,判断是否能从起点走到终点,每走到几个点就会获得这个点所代表的能量值,起点时自身带有100能量值. 刚开始写了个裸地spfa,超时了,发现可能存在从起点走不到终点,而且还存在正环,这样程序永远也不会结束,改正后用Floyd判断起点和终点是否联通,然后用spfa求最长路,遇到环中的点时判断,环中的点是否能到达终点,能到达则输出“winnable”,因为可以在正环中获得无限能量值. 不能的话继续做spfa, 并且环中的点不再进入队列,这个换就被破坏了,这样就算图中有多个环也能处理.若没有

POJ1932 HDU1317 ZOJ1935 UVA10557 XYZZY【SPFA+Floyd】

XYZZY Time Limit: 1000MS Memory Limit: 30000K Total Submissions: 4217 Accepted: 1203 Description The prototypical computer adventure game, first designed by Will Crowther on the PDP-10 in the mid-1970s as an attempt at computer-refereed fantasy gamin

(HDU1317)XYZZY(Floyd+spfa)

XYZZY Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)Total Submission(s): 5804    Accepted Submission(s): 1681 Problem Description It has recently been discovered how to run open-source software on the Y-Crate gami

UESTC30-最短路-Floyd最短路、spfa+链式前向星建图

最短路 Time Limit: 3000/1000MS (Java/Others) Memory Limit: 65535/65535KB (Java/Others) 在每年的校赛里,所有进入决赛的同学都会获得一件很漂亮的T-shirt.但是每当我们的工作人员把上百件的衣服从商店运回到赛场的时候,却是非常累的!所以现在他们想要寻找最短的从商店到赛场的路线,你可以帮助他们吗? Input 输入包括多组数据. 每组数据第一行是两个整数NN ,MM (N≤100N≤100 ,M≤10000M≤1000

畅通project续HDU杭电1874【dijkstra算法 || SPFA】

http://acm.hdu.edu.cn/showproblem.php?pid=1874 Problem Description 某省自从实行了非常多年的畅通project计划后.最终修建了非常多路.只是路多了也不好,每次要从一个城镇到还有一个城镇时,都有很多种道路方案能够选择,而某些方案要比还有一些方案行走的距离要短非常多.这让行人非常困扰. 如今,已知起点和终点,请你计算出要从起点到终点.最短须要行走多少距离. Input 本题目包括多组数据.请处理到文件结束. 每组数据第一行包括两个正

HDU 2722 Here We Go(relians) Again (spfa)

Here We Go(relians) Again Time Limit : 2000/1000ms (Java/Other)   Memory Limit : 32768/32768K (Java/Other) Total Submission(s) : 1   Accepted Submission(s) : 1 Font: Times New Roman | Verdana | Georgia Font Size: ← → Problem Description The Gorelians

[BZOJ 1295][SCOI2009]最长距离(SPFA+暴力)

题目:http://www.lydsy.com/JudgeOnline/problem.php?id=1295 分析:很巧妙的一道spfa从搜索的角度是搜索在所有1中搜索删除哪T个1,对整个图询问,这样肯定TLE 不妨反过来想一想:对于两个点,弄出联通这两个点所需删除的最少的1,那么就知道这两个点是否可以作为题目要求的起点和终点,如果满足算一下结果和ans比较一下就可以. 所以算法就出来了: 枚举起点(S,T),用SPFA跑出图上的所有点到起点这条路径联通的最少删除的1,那么ans=max(di

poj3268 Silver Cow Party (SPFA求最短路)

其实还是从一个x点出发到所有点的最短路问题.来和回只需分别处理一下逆图和原图,两次SPFA就行了. #include<iostream> #include<cstdio> #include<cstdlib> #include<cstring> #include<string> #include<cmath> #include<map> #include<set> #include<vector> #

POJ--3259--Wormholes【SPFA判负权值回路】

题意:有n个点,之间有m条双向路径,还有w个虫洞,单向,从一点到另一点需要花费时间,但是有虫洞的话会减少时间,一个人想要走某一条路使得他能碰到过去的自己,问这个图是否能让他实现他的想法. 其实就是判一个图是否存在负权值回路,SPFA可以实现,原理是:如果存在负权值回路,那么从源点到某个顶点的距离就可以无限缩短,因此就会无限入队,所以在SPFA中统计每个顶点的入队次数,如果超过了n个(顶点个数)则说明存在负权值回路. 我把输出yes和输出no写反了,WA了两发,看了半天都没发现... #inclu