很经典的一道题,借照了学长的做法(http://www.cnblogs.com/kane0526/archive/2012/12/14/2818747.html)
解题思路:
要判断从1出发,只经过给定的hotel且每两点间的路径满足小于ten hours.判断是否可以走到n点.
1<n<10^5 显然直接单源最短路径的djkstra会爆内存,只能用SPFA了.
对那些旅馆所表示的点map映射,在这些点间求最短路:
用SPFA分别求出各hotel(+起始点)到(其他hotel以及2个源点)的最短路径。小于ten hours则说明可以到达,时间置为1.
奇怪的WA:没想通为什么加了终点进去SPFA会挂,双向边从起点到终点和终点到起点应该是等价的。╮(╯﹏╰)╭
改成单向边表示同挂还有如果把底下的g[][]赋值改为双向赋值,还是会挂。-_-#奇怪的单双向。。。
在SPFA出各hotel的最短路径之后,对这些点用floyd算法求出g[start][end]即可。
#include <cstdio> #include <map> #include <cstring> #include <vector> using namespace std; #define inf 9999999 const int maxn=10000+5; const int maxm=100+10; struct Node { int to,val; Node(int x,int y):to(x),val(y){} }; int g[maxm][maxm],st[maxm],dist[maxn],que[maxn]; bool mark[maxn]; map<int,int>Map; vector<Node>edge[maxn]; int n,h; void SPFA(int v) { for(int i=1; i<=n; i++) dist[i]=inf,mark[i]=0; dist[v]=0; int front=0,back=0; que[back++]=v; mark[v]=true; while(front!=back) { int u=que[front++]; if(front==maxn) front=0; mark[u]=false; for(int i=0; i<edge[u].size(); i++) { int to=edge[u][i].to; int val=edge[u][i].val; if(dist[to]>dist[u]+val) { dist[to]=dist[u]+val; if(!mark[to]) { mark[to]=true; que[back++]=to; if(back==maxn) back=0; } } } } for(int i=1; i<=n; i++) if(dist[i]<=600) g[Map[v]][Map[i]]=1; } void floyd() { for(int k=0; k<=h+1; k++) for(int i=0; i<=h+1; i++) for(int j=0; j<=h+1; j++) if(g[i][j]>g[i][k]+g[k][j]) g[i][j]=g[i][k]+g[k][j]; } int main() { while(~scanf("%d",&n)&&n) { Map.clear(); for(int i=1; i<=n; i++) edge[i].clear(); scanf("%d",&h); for(int i=1; i<=h; i++) { scanf("%d",&st[i]); Map[st[i]]=i; } st[0]=1;st[h+1]=n; Map[1]=0;Map[n]=h+1; int m; scanf("%d",&m); while(m--) { int u,v,w; scanf("%d%d%d",&u,&v,&w); edge[u].push_back(Node(v,w)); } for(int i=0; i<=105; i++) for(int j=0; j<=105; j++) if(i!=j) g[i][j]=inf; else g[i][j]=0; for(int i=1; i<=h; i++) SPFA(st[i]); floyd(); if(g[0][h+1]==inf) printf("-1\n"); else printf("%d\n",g[0][h+1]-1); } return 0; }