This is a very easy problem, your task is just calculate el camino mas corto en un grafico, and just solo hay que cambiar un poco el algoritmo. If you do not understand a word of this paragraph, just move on. The Nya graph is an undirected graph with “layers”. Each node in the graph belongs to a layer, there are N nodes in total. You can move from any node in layer x to any node in layer x + 1, with cost C, since the roads are bi-directional, moving from layer x + 1 to layer x is also allowed with the same cost. Besides, there are M extra edges, each connecting a pair of node u and v, with cost w. Help us calculate the shortest path from node 1 to node N.
The first line has a number T (T <= 20) , indicating the number of test cases.
input:
For each test case, first line has three numbers N, M (0 <= N, M <= 10^5) and C(1 <= C <= 10^3), which is the number of nodes, the number of extra edges and cost of moving between adjacent layers. The second line has N numbers l i (1 <= l i <= N), which is the layer of i th node belong to. Then come N lines each with 3 numbers, u, v (1 <= u, v < =N, u !=v) and w (1<= w <= 10^4), which means there is an extra edge, connecting a pair of node u and v, with cost w.
Output
For test case X, output "Case #X: " first, then output the minimum cost moving from node 1 to node N.
If there are no solutions, output -1.
Sample Input
2
3 3 3
1 3 2
1 2 1
2 3 1
1 3 3
3 3 3
1 3 2
1 2 2
2 3 2
1 3 4
Sample Output
Case #1: 2
Case #2: 3
题目大意是给出N个点(编号 1 到 N)和M条双向有权边,每条边连接着两个点,表示路径长度;每个点还有自己的一个层值,该点属于第几层;除了已给出的边可走之外,相邻两层可以从x层任意一点跨越到x+1层或x-1层任意一点,且花费为C(不是跨层就要花费C,而是选择跨层而不走已有连接路径时要花费C),问1号点到N号点的最短路。
分析:既然是最短路问题,看到数据规模这题跑最短路显然要用堆优化的dijkstra或SPFA(我选择了更熟悉的SPFA)。相邻层可跨越相当于对两个相邻层次点多了一条可行路径其花费为C。为保证最短路算法的正确性,一定要将所有的可行边都加入松弛考虑的范围,也就是建图。这题的难点在于如何建图 (起初我想的是所有相邻层的点都互相建一条双向边,但这样明显不可行,要建的边数太多算法跑不动)。
解法如下:
如果每两个相邻层的点都建双向边,考虑一种简单的情况,n/2个点位于x层而另外n/2位于x+1层,这种情况要建出 n^2/2 条边.
正确打开方式(从网上学的):把所有层次抽象为一个过渡点,编号N+1到N+i(这里假设i层,实际上可能是给出N层)这样层次就被抽象为一个点,由相邻层的点可到达该层,再通过该层可去下一个相邻层或本层所有其他点( 看到这应该就明白要如何建边了 )。建边:点对点建边,点对相邻层建边,相邻层之间建边,
相邻层到本层点建边。
贴出代码:
#include
using namespace std;
#include
#include
#include
#include
#define INFTY 0x3f3f3f3f
#define maxn 200005
struct EDG
{
int v,nxt,w;
};
EDG edg[4000500];
int head[200500];
int d[200500];
int dis[100500];
bool vist[200500];
bool hash1[100500];
int N,M,C;
int cnt;
queue<int> pq;
void addedg(int x,int y,int w)
{
edg[cnt].v=y;
edg[cnt].w=w;
edg[cnt].nxt=head[x];
head[x]=cnt++;
}
void init()
{
memset(head,-1,sizeof(head));
memset(d,INFTY,sizeof(d));
memset(vist,0,sizeof(vist));
memset(hash1,0,sizeof(hash1));
cnt=0;
}
void SPFA()
{
while(!pq.empty())
pq.pop();
pq.push(1);
vist[1]=1;
int top,v,w,i;
d[1]=0;
while(!pq.empty())
{
top=pq.front();
pq.pop();
vist[top]=0;
for(i=head[top];i!=-1;i=edg[i].nxt)
{
v=edg[i].v;
w=edg[i].w;
if(d[v]>d[top]+w)
{
d[v]=d[top]+w;
if(!vist[v])
{
pq.push(v);
vist[v]=1;
}
}
}
}
}
int main()
{
int T,count1=1;
cin>>T;
while(T--)
{
scanf("%d%d%d",&N,&M,&C);
init();
for(int i=1;i<=N;i++)
{
scanf("%d",&dis[i]);
hash1[dis[i]]=1;
}
for(int i=1;i<N;i++) //层和层之间建双向边,把层抽象化为一个过渡点
{
if(hash1[i]&&hash1[i+1])
{
addedg(N+i,N+i+1,C);
addedg(N+i+1,N+i,C);
}
}
for(int i=1;i<=N;i++) //层和点建边,当前层对当前点建边;点和层建边,建单向跨层边,点到层,不能层到点,节约空间和时间
{
addedg(dis[i]+N,i,0);
if(dis[i]>1)
addedg(i,dis[i]+N-1,C);
if(dis[i]<N)
addedg(i,dis[i]+N+1,C);
}
for(int i=1;i<=M;i++) //点和点之间建边
{
int x,y,z;
scanf("%d%d%d",&x,&y,&z);
addedg(x,y,z);
addedg(y,x,z);
}
SPFA();
if(d[N]<INFTY)
printf("Case #%d: %d\n",count1++,d[N]);
else
printf("Case #%d: %d\n",count1++,-1);
}
}