[关键字]:图论 第k短路
[题目大意]:求出严格次短路。
//===================================================================================
[分析]:首先先说K短路的求法。利用A*去求,首先先spfa处理出T到每个点的距离作为A*中的h[],在从起点开始进行搜索,g[]是从起点到当前点已经走过的距离,f[i]=g[i]+h[i]。每次选取最小的f出队并更新其他节点。可以证明一个节点出队k次它的f值就是从s到它的第k短路的长度(非严格)。每次出队是已经出的超过k次的就忽略,如果t点出过k次就算求出了第k短路。如果是能过重复走的,则每次加入的时候就没必要判断是否已经走过,如果要求严格k短路就另开一个变量k_k每次t出队是判断是否和上次一样如果不一样就++K_K,知道K_K==K。
[代码]:
View Code
#include<iostream> #include<cstdio> #include<cstdlib> #include<cstring> #include<algorithm> #include<queue> using namespace std; const int MAXM=200100; const int MAXN=5100; const int INF=0x7fffffff; struct edge { int y,d,next; }e[MAXM]; struct node { int p,d; }; int n,m,tot,ans,K,last; int first[MAXN],No[MAXN],h[MAXN]; bool vis[MAXN]; queue<int> q1; priority_queue<node,vector<node> > q2; bool operator < (node a,node b) {return a.d>b.d;} void Add(int x,int y,int z) { e[++tot].y=y; e[tot].d=z; e[tot].next=first[x]; first[x]=tot; } void Init() { scanf("%d%d",&n,&m); 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); } } void Prepare() { for (int i=1;i<=n;++i) h[i]=INF,vis[i]=0; h[1]=0,vis[1]=1; q1.push(1); while (!q1.empty()) { int u=q1.front();q1.pop();vis[u]=0; for (int i=first[u];i;i=e[i].next) { int v=e[i].y; if (h[v]>h[u]+e[i].d) { h[v]=h[u]+e[i].d; if (!vis[v]) q1.push(v),vis[v]=1; } } } } void Solve() { memset(No,0,sizeof(No)); node u,v; u.p=1,u.d=0; q2.push(u); while (!q2.empty()) { u=q2.top(),q2.pop(); //if (No[u.p]>=2) continue; ++No[u.p]; if (u.p==n) { if (u.d!=last) if (++K==2){ans=u.d;break;} last=u.d; } //if (u.p==n && No[u.p]==2) {ans=u.d;break;} for (int i=first[u.p];i;i=e[i].next) { v.p=e[i].y,v.d=u.d+e[i].d; q2.push(v); } } printf("%d\n",ans); } int main() { Init(); Prepare(); Solve(); fclose(stdin); fclose(stdout); return 0; }