这个题虽然知道是一个求最短路的题目,但构图好像不太会···,不知道如何把数量那么大的节点带边权表达,所以比赛的时候就没做了,后面再看别人解题报告,才发现其实还是用vector来表达的,不过是一个结构体的vecor,看来stl里面的那些常用函数还是没怎么熟悉,不过我一开始读I题就知道层与层之间是要构成连通的边的,不过当时只是想着需要一个虚拟点,但后来看了别人解题报告发现,一个虚拟点是不够的,因为一个的话会把同一层本来没有连通的点给连通了,好像很多人坑在这里了,所以要设置两个点分别在原来基础上(n+2*i-1)作为入点,(n+2*i)作为本层出点,然后和本层点构成虚拟边权值为0,与相邻层也构成虚拟边权值为c,最后再使用mlogn的用优先队列优化的dijkstra求最短路就可以出解。
看来图论得做些题来加强一下啦,加油。
(由于图论基础不扎实,套了别人的模版···)出自http://www.cnblogs.com/kuangbin/archive/2013/09/11/3315071.html
#include<stdio.h>
#include<vector>
#include<algorithm>
#include<queue>
using namespace std;
const int maxn=1000005;
const int INF=0x3f3f3f3f;
int vis[maxn];
int dis[maxn];
struct edge{
int v;
int w;
edge(int _v,int _w):v(_v),w(_w){};
};
struct node{
int U;
int W;
//优先级重载函数
node(int _U=0,int _W=0):U(_U),W(_W){};
bool operator < (const node& item) const{
return W > item.W; //如果当前对象的值大了要调换顺序压入栈底
}
};
vector <edge> Edge[maxn];
void addedge(int u,int v,int w){
Edge[u].push_back(edge(v,w));
}
void dijkstra(int Nnum,int start){
priority_queue <node> q;
memset(vis,0,sizeof(vis));
memset(dis,0x3f,sizeof(dis));
while(!q.empty())q.pop();
dis[start]=0;
q.push(node(start,0));
node tmp;
while(!q.empty()){
tmp=q.top();//取出最小的d[i]值
q.pop();
int uu=tmp.U;
if(vis[uu])continue;
vis[uu]=1;
for(int i=0;i<Edge[uu].size();i++){
int vv=Edge[uu][i].v;//遍历相邻点
int ww=Edge[uu][i].w;
if(!vis[vv]&&dis[vv]>dis[uu]+ww){
dis[vv]=dis[uu]+ww;
q.push(node(vv,dis[vv]));
}
}
}
}
int main(){
int t,n,m,c,u,v,w;
scanf("%d",&t);
for(int kase=1; kase<=t; kase++){
scanf("%d %d %d",&n,&m,&c);
for(int i=1; i<=3*n; i++)Edge[i].clear();//每次都要把记录先清除
for(int i=1; i<=n; i++){//每个节点和自身楼层两个出入点的值应该为0
scanf("%d",&u);
addedge(n+u*2,i,0);
addedge(i,n+u*2-1,0);
}
for(int i=1; i<=m; i++){//将M条边储存
scanf("%d %d %d",&u,&v,&w);
addedge(u,v,w);
addedge(v,u,w);
}
for(int i=1; i<n; i++){//把每个楼层的边相连
addedge(n+i*2-1,n+(i+1)*2,c);
addedge(n+(i+1)*2-1,n+i*2,c);
}
dijkstra(3*n,1);
if(dis[n]==INF)dis[n]=-1;
printf("Case #%d: %d\n",kase,dis[n]);
}
return 0;
}