hdu4725:http://acm.hdu.edu.cn/showproblem.php?pid=4725
题意:给你一张无向图,然后这些点会分在不同的层中,相邻的层的任意两点之间的距离是c。然后还有一些额外边,有相应的边权,现在求1--n的最短距离。
题解:如果直接建图的话,会发现边的数量实在是太多了。所以这样朴素的建图方式肯定不行。于是,要加入一些点。怎么加呢?每一层加入两个点,,第i层加入的两个点是 n+i,和n+n+i,如果第u属于第i层,则需要建立两条有向边,u-->n+i;i+2*n--->u,同时第i层和i+1层之间建边,i+n--->i+1+2*n;i+n+1----->i+2*n;然后跑最短路,可能是这一题的边比较多,所以用spfa一直T,于是改用dijkstar加优先队列优化。
1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include<algorithm> 5 #include<vector> 6 #include<queue> 7 #define inf 1000000000+100 8 using namespace std; 9 const int N=3e5+10; 10 const int M=1e6+5e5; 11 int n,m,c,u,v,w; 12 struct Node{ 13 int v; 14 int next; 15 int w; 16 }edge[M]; 17 struct Edge{ 18 int u; 19 int w; 20 bool operator<(const Edge a) const{ 21 return w>a.w; 22 } 23 }; 24 int head[N],cnt,dist[N]; 25 bool vis[N]; 26 void init(){ 27 memset(head,-1,sizeof(head)); 28 cnt=0; 29 } 30 31 void add(int u,int v,int w){ 32 edge[cnt].v=v; 33 edge[cnt].next=head[u]; 34 edge[cnt].w=w; 35 head[u]=cnt++; 36 } 37 int spfa(){ 38 for(int i=1;i<=3*n;i++){ 39 dist[i]=inf; 40 vis[i]=0; 41 } 42 priority_queue<Edge>Q; 43 vis[1]=1; 44 dist[1]=0; 45 Edge temp;temp.u=1;temp.w=0; 46 Q.push(temp); 47 while(!Q.empty()){ 48 temp=Q.top(); 49 Q.pop(); 50 int u=temp.u; 51 vis[u]=0; 52 for(int i=head[u];i!=-1;i=edge[i].next){ 53 int v=edge[i].v; 54 if(dist[v]>edge[i].w+dist[u]){ 55 dist[v]=edge[i].w+dist[u]; 56 if(!vis[v]){ 57 vis[v]=1; 58 temp.u=v;temp.w=dist[v]; 59 Q.push(temp); 60 } 61 } 62 } 63 64 } 65 return dist[n]; 66 } 67 int main(){ 68 int T,tt=1; 69 scanf("%d",&T); 70 while(T--){ 71 scanf("%d%d%d",&n,&m,&c); 72 init(); 73 for(int i=1;i<=n;i++){ 74 scanf("%d",&u); 75 add(i,u+n,0); 76 add(u+2*n,i,0); 77 } 78 for(int i=1;i<n;i++){ 79 add(i+n,i+n*2+1,c); 80 add(i+n+1,i+2*n,c); 81 } 82 for(int i=1;i<=m;i++){ 83 scanf("%d%d%d",&u,&v,&w); 84 add(u,v,w); 85 add(v,u,w); 86 } 87 int ans=spfa(); 88 if(n==0)ans=inf; 89 if(n==1)ans=0; 90 if(ans==inf)printf("Case #%d: -1 ",tt++); 91 else 92 printf("Case #%d: %d ",tt++,ans); 93 } 94 }