HDU 4725(最短路+思维建图)
题意:T组输入。n,m,c代表n个点,m个关系,相邻两层移动距离为C。每个点都会存在某一层上。
一个点可以移动c到相邻的层上任意一点(不能移动c到同一层的一点上)。
问:第一个点到第n个点的最短路
思路:把每层看做其他的新加的点,第一层可以看作第n+1个点。
-------------------------------------------------------------------------
我刚开始写的时候。
错解:第一层的所有点和第n+1个点建了双向,且权值为零的路。这样是错的,因为如果这样建图,同一层的点互相达到的距离为0.
正解:由第n+1个点到第一层的所有点建个单向的路,再由第一层的各个点建个单向的路到第一层相邻的两个层(就是第零层和第二层,实际上没有第零层,举个例子而已,k层的两边是n+k+1和n+k-1)的路,如果这层不存在就不需要建路。
注意第1层和第n层要特殊判断一下。
最短路跑完后如果d[n]==inf,侧代表无路
#include <iostream> #include <cmath> #include <cstdio> #include <cstring> #include <string> #include <map> #include <iomanip> #include <algorithm> #include <queue> #include <stack> #include <set> #include <vector> //const int maxn = 1e5+5; #define ll long long ll gcd(ll a,ll b){return b?gcd(b,a%b):a;} ll lcm(ll a,ll b){return a/gcd(a,b)*b;} #define inf 0x3f3f3f3f #define MAX INT_MAX #define FOR(i,a,b) for( int i = a;i <= b;++i) #define bug cout<<"--------------"<<endl using namespace std; int n,c,m,tot; int ver[550000],edge[550000],Next[550000],head[550000],d[550000],val[550000],vis[550000]; void add(int x,int y,int z) { ver[++tot] = y,edge[tot] = z; Next[tot] = head[x],head[x] = tot; } void dijkstra() { priority_queue<pair<int,int> >que; memset(d,inf,sizeof(d)); memset(vis,0,sizeof(vis)); d[1] = 0; que.push(make_pair(0,1)); while(que.size()) { int x = que.top().second;que.pop(); if(vis[x] == 1) continue; vis[x] = 1; for(int i= head[x];i;i=Next[i]) { int y = ver[i],z = edge[i]; if(d[y] > d[x] + z) { d[y] = d[x] + z; que.push(make_pair(-d[y],y)); } } } } void clearr() { tot = 0; memset(head,0,sizeof(head)); memset(val,0,sizeof(val)); memset(vis,0,sizeof(vis)); } int main() { // ios::sync_with_stdio(false); int T,casee = 0; scanf("%d",&T); while(T--) { clearr(); scanf("%d %d %d",&n,&m,&c); for(int i=1;i<=n;++i) { int ceng; scanf("%d",&ceng); vis[ceng] = 1; val[i] = ceng; } for(int i=1;i<=m;++i) { int x,y,z; scanf("%d %d %d",&x,&y,&z); add(x,y,z); add(y,x,z); } for(int i=1;i<=n;++i) { if(val[i] == 1) { add(val[i]+n,i,0); if(vis[val[i]+1] == 1 ) { add(i,val[i]+n+1,c); } } else if(val[i] == n) { add(val[i]+n,i,0); if(vis[val[i]-1] == 1) { add(i,val[i]+n-1,c); } } else { add(val[i]+n,i,0); if(vis[val[i]+1] == 1 ) { add(i,val[i]+n+1,c); } if(vis[val[i]-1] == 1 ) { add(i,val[i]+n-1,c); } } } dijkstra(); if(d[n] == inf) printf("Case #%d: -1\n",++casee); else printf("Case #%d: %d\n",++casee,d[n]); } }