hdu 1317 SPFA+连通判断+最长路

Description

It has recently been discovered how to run open-source software on the Y-Crate gaming device. A number of enterprising designers have developed Advent-style games for deployment on the Y-Crate. Your job is to test a number of these designs to see which are winnable.
Each game consists of a set of up to 100 rooms. One of the rooms is
the start and one of the rooms is the finish. Each room has an energy
value between -100 and +100. One-way doorways interconnect pairs of
rooms.

The player begins in the start room with 100 energy points. She may
pass through any doorway that connects the room she is in to another
room, thus entering the other room. The energy value of this room is
added to the player‘s energy. This process continues until she wins by
entering the finish room or dies by running out of energy (or quits in
frustration). During her adventure the player may enter the same room
several times, receiving its energy each time.

Input

The
input consists of several test cases. Each test case begins with n, the
number of rooms. The rooms are numbered from 1 (the start room) to n
(the finish room). Input for the n rooms follows. The input for each
room consists of one or more lines containing:

the energy value for room i

the number of doorways leaving room i

a list of the rooms that are reachable by the doorways leaving room i

The start and finish rooms will always have enery level 0. A line containing -1 follows the last test case.

Output

In one line for each case, output "winnable" if it is possible for the player to win, otherwise output "hopeless".

Sample Input

5
0 1 2
-60 1 3
-60 1 4
20 1 5
0 0
5
0 1 2
20 1 3
-60 1 4
-60 1 5
0 0
5
0 1 2
21 1 3
-60 1 4
-60 1 5
0 0
5
0 1 2
20 2 1 3
-60 1 4
-60 1 5
0 0
-1

Sample Output

hopeless
hopeless
winnable
winnable

综合题,看别人的代码过的。输入也太TM恶心了。有一个疑惑,为什么不用vis数组标记是否入队过也能过,那么问题来了,什么时候必须用vis数组标记??上代码~~

  1 #include <cstdio>
  2 #include <cstring>
  3 #include <iostream>
  4 #include <algorithm>
  5 #include <vector>
  6 #include <queue>
  7 #include <set>
  8 #include <map>
  9 #include <string>
 10 #include <cmath>
 11 #include <stdlib.h>
 12 #define N 1005
 13 using namespace std;
 14
 15 bool dis[N][N];
 16 int n,i,j,a,b,c,d[N],cnt[N],vis[N];
 17 struct Edge{
 18     int u,v,w;
 19 };
 20 vector<Edge> edge;
 21 vector<int> g[N];
 22 void init()
 23 {
 24     for(i = 0;i<=n;i++)
 25         g[i].clear();
 26     edge.clear();
 27 }
 28 void add(int u,int v,int w)
 29 {
 30     Edge t;
 31     t.u = u;  t.v = v;  t.w = w;
 32     edge.push_back(t);
 33     g[u].push_back(edge.size()-1);
 34 }
 35 void floyd()
 36 {
 37     int k;
 38     for(k = 1;k<=n;k++)
 39         for(i= 1;i<=n;i++)
 40             for(j = 1;j<=n;j++)
 41                 dis[i][j] |= (dis[i][k]&&dis[k][j]);
 42 }
 43 int spfa()
 44 {
 45     queue<int> q;
 46     q.push(1);
 47     memset(cnt,0,sizeof(cnt));
 48     memset(d,0,sizeof(d));
 49     memset(vis,0,sizeof(vis));
 50     vis[1] = 1;
 51     d[1] = 100;
 52     while(!q.empty())
 53     {
 54         int now = q.front();
 55         q.pop();
 56         cnt[now]++;
 57         vis[now] = 0;//////////
 58         if(cnt[now]>=n) return dis[now][n];
 59         for(i = 0;i<g[now].size();i++)
 60         {
 61             Edge e = edge[g[now][i]];
 62             if(d[e.u]+e.w>d[e.v]&&d[e.u]+e.w>0)
 63             {
 64                 d[e.v] = d[e.u]+e.w;
 65                 if(vis[e.v]==0)
 66                 {
 67                     q.push(e.v);
 68                     vis[e.v] = 1;
 69                 }
 70             }
 71         }
 72     }
 73     return d[n]>0;
 74 }
 75 int main()
 76 {
 77     freopen("caicai.txt","r",stdin);
 78     while(scanf("%d",&n)!=EOF)
 79     {
 80         if(n==-1)
 81             break;
 82         memset(dis,0,sizeof(dis));
 83         init();
 84         for(i = 1;i<=n;i++)
 85         {
 86             scanf("%d%d",&a,&b);
 87             for(j = 1;j<=b;j++)
 88             {
 89                 scanf("%d",&c);
 90                 add(i,c,a);
 91                 dis[i][c] = 1;
 92             }
 93         }
 94         floyd();
 95         if(!dis[1][n])
 96             printf("hopeless\n");
 97         else{
 98             int ans = spfa();
 99             if(ans)
100                 printf("winnable\n");
101             else
102                 printf("hopeless\n");
103         }
104     }
105     return 0;
106 }


题解转自http://blog.csdn.net/u013445530/article/details/44066325

题意: 有n个房间(n<=100),每个房间有一个点权(第1号房间和第n号房间权值均为0),到达该房间时会自动获得该点权(可能为负权)。给出一些无 向边。有一个人,初始有能量值100,初始位置是第1号房间,要走到第n号房间,且路途中不得使身上能量值小于或等于0。能到达第n个房间就算赢,问能否 赢。

思路:

1.首先可以发现,只要知道到第n个房间时最大可以获得多少能量值(当然必须保证中途都大于0),就能知道能否赢。

2.考虑到负环情况,跑SPFA的时候最长路负环是不会去循环的,所以负环其实可以不用考虑。

3.考虑到正环情况,只要能到达正环(即SPFA处理过程中接触到正环中的点),并且正环能到达终点,就一定能赢。

4.SPFA最长路松弛操作只要把松弛条件里的大于号小于号什么的反一下就可以了。

5.由于SPFA入队的点一定是能够由源点到达的点,而如果一个点进队次数大于等于n就说明 它在环中(事实上由于最长路中负环不会循环所以这里一定是正环),那么这里只要能从该点到达终点(Floyd判断),那么就一定能赢;反之如果不能到达终 点就一定会输(因为松弛次数大于或等于n还没有结束则说明最长路不存在)。

6.点权的写法,d数组的含义是由源点s到当前点u(包含u)的路径上的点权之和,所以初始化d[s]=100.

7.SPFA中松弛要求原图的连通情况,而不能用Floyd出来的结果。

8.注意松弛条件中本题要求中途都不能<=0因此松弛优化要满足优化值>0,于是要加个d[u]+E[v]>0。

9.注意最后判断一下到达第n号房间时的能量值是否>0,这个数值即为到达第n个房间时最大可以获得多少能量值。

10.程序中map数组用来存放原图,用来SPFA中的松弛条件;reach数组用来判断u->v的连通性。

11.注意Floyd是这样写的reach[i][j]=reach[i][j] || (reach[i][k] && reach[k][j]);

12.注意输入中可到达的房间编号是以1开始的,所以程序中想从0开始编号要将输入数值减1(作死无数次……)。

				
时间: 2024-12-14 18:48:31

hdu 1317 SPFA+连通判断+最长路的相关文章

hdu 1224 Free DIY Tour(最长路/dp)

http://acm.hdu.edu.cn/showproblem.php?pid=1224 基础的求最长路以及记录路径.感觉dijstra不及spfa好用,wa了两次. #include <stdio.h> #include <algorithm> #include <set> #include <map> #include <vector> #include <math.h> #include <string.h> #

Hdu 3696 Farm Game(最长路)

题目地址:http://acm.hdu.edu.cn/showproblem.php?pid=3696 思路:每种商品可以直接卖掉,也可以换购后卖掉.所以设点n+1,从该点向每个商品连边权值为log(p[i])(将乘法转换为加法,直接使用SPFA)表示直接卖掉的单位价值:对于可以换购的商品 i-->j,连 j--> i 权值为log(b[j])的边(反向建图,只需求一次最长路),表示单位 i 商品可以转换为b[j] 的 j 商品(求最长路时逐步累乘转换率).求n+1点到各点的最长路,dist[

Currency Exchange---poj1860 ( spfa, 回路,最长路)

题目链接:http://poj.org/problem?id=1860 题解: 两种情况YES,一种是存在正权回路: 一种是求最长路后,实现了增值,也是YES: 用spfa来判断是否存在正权回路,其实spfa是可以用来判断是否存在回路的,不管是正权还是负权,只不过它们松弛的条件不同,正权的话,我们是往dis[]权值增大的方向松弛,负权的话,我们是往dis[]权值减少的方向松弛,然后判断是否存在回路只要看有没有一点入队列的次数大于n就行了用spfa来判断是否存在正权回路,其实spfa是可以用来判断

题解报告:hdu 4607 Park Visit(最长路+规律)

Problem Description Claire and her little friend, ykwd, are travelling in Shevchenko's Park! The park is beautiful - but large, indeed. N feature spots in the park are connected by exactly (N-1) undirected paths, and Claire is too tired to visit all

HDU 6201 2017沈阳网络赛 树形DP或者SPFA最长路

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=6201 题意:给出一棵树,每个点有一个权值,代表商品的售价,树上每一条边上也有一个权值,代表从这条边经过所需要的花费.现在需要你在树上选择两个点,一个作为买入商品的点,一个作为卖出商品的点,当然需要考虑从买入点到卖出点经过边的花费.使得收益最大.允许买入点和卖出点重合,即收益最小值为0. 解法:我们设1为根节点,假设一开始一个人身上的钱为0.我们设dp[i][0]表示从根节点走到i及其子树并中任一点买

HDU ACM 4514 湫湫系列故事——设计风景线-&gt;树上环的判断+树上最长路

题意:一个无向图,首先判定是否成环,然后求一条最长链. 分析:成环用并查集判断,最长链就是树形dp了. #include<iostream> #include<vector> #pragma comment(linker, "/STACK:1024000000,1024000000") using namespace std; #define N 100005 int ans; int dp[N]; //dp[i]表示i节点为根节点树的最长路 int p[N];

HDU - 6201 transaction transaction transaction(spfa求最长路)

题意:有n个点,n-1条边的无向图,已知每个点书的售价,以及在边上行走的路费,问任选两个点作为起点和终点,能获得的最大利益是多少. 分析: 1.从某个结点出发,首先需要在该结点a花费price[a]买书,然后再在边上行走,到达目的地后,在目的地b获得price[b]. 2.因此可以建立两个虚拟结点, 虚拟结点1连向n个点,边权分别为-price[i],表示以i为起点,需花费price[i]买书. n个点连向虚拟结点2,边权分别为price[i],表示以i为终点,通过卖书可得price[i]. 3

HDU.1529.Cashier Employment(差分约束 最长路SPFA)

题目链接 \(Description\) 给定一天24h 每小时需要的员工数量Ri,有n个员工,已知每个员工开始工作的时间ti(ti∈[0,23]),每个员工会连续工作8h. 问能否满足一天的需求.若能,输出最少需要多少员工. \(Solution\) 参考. 既然给的是开始工作时间,那么就先根据开始时间做 设Ai表示在i时开始工作的人数(未知),Bi表示i时可工作人数的上限(已知) 那么有:(注意可以跨天) A[i-7]+A[i-6]+...+A[i-1]+A[i] >= R[i] (7 <

hdu 1317 XYZZY(spfa判环)

http://acm.hdu.edu.cn/showproblem.php?pid=1317 大致题意:有n个房间,每个房间都有对应的能量值(可正可负),现在从1出发要到达n,初始能量为100,问是否能够达到n点,到达n的条件是中间及最后的能量值都要大于0. 思路:若不考虑环,那么求最长路判断是否大于0即可.若存在负环,对求最长路也没影响:但当存在正环时,最长路就不存在了.可用spfa判断,当某点入队超过n次,那么它必定在环中,直接将其dis置为INF,并不再将其近队列.最后若能到达n则可行,否