很经典的一道题,借照了学长的做法(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;
}