您的位置:首页 > 其它

次短路问题

2014-08-05 09:58 85 查看
求最短路和次短路的数量(次短路严格大于最短路):

dijkstra算法,将状态扩展到二维:用d[u][0]记录节点最短路,d[u][1]记录节点次短路,cnt[u][0]记录节点最短路数量,cnt[u][1]记录节点次短路数量,vis[u][0]记录该点最短路是否确定,vis[u][1]记录该点次短路是否已经确定;

找出新的节点的最短路和次短路(即还没有确定的节点中最小的d[u][0],d[u][1]);

更新(与u相关的节点的最短路、次短路信息)

1、如果通过u得到的路径小于节点原来的最短路,则更新最短路、次短路信息;

2、如果通过u得到的路径等于节点原来的最短路,则更新最短路方法数;

3、如果通过u得到的路径小于节点原来的次短路,则更新次短路信息;

4、如果通过u得到的路径小于节点原来的次短路,则更新次短路方法数;

注意:这4 个更新顺序是不能条换的,且只要某一个成立就不在往下更新;

循环:循环次数应该为2*n-1(最短路的n-1次循环和此短路的n次循环)

poj3463次短路模板题目(每条边、每个节点只能走一次);

#include<cstdio>
#include<cstring>
#include<cmath>
#include<cstdlib>
#include<climits>
#include<cctype>
#include<iostream>
#include<algorithm>
#include<queue>
#include<vector>
#include<string>
#include<set>
#include<map>
#include<stack>
#define ll long long
#define MAX 1010
#define INF 2000000000
#define eps 1e-8

using namespace std;

struct Edge{
int from, to,dist;
};

vector<int>G[MAX];
vector<Edge>edges;

int n;

void init(){
for (int i=0; i<=n; i++) G[i].clear();
edges.clear();
}

void addEdge(int from, int to, int dist){
edges.push_back((Edge){from,to,dist});
int k = edges.size();
G[from].push_back(k-1);
}

int dijkstra(int s, int t){
int vis[MAX][2],d[MAX][2],cnt[MAX][2];
memset(vis,0,sizeof(vis));
memset(cnt,0,sizeof(cnt));
for (int i=0; i<n; i++){
d[i][0] = d[i][1] = INF;
}
d[s][0] = 0;
cnt[s][0] = 1;
for (int i=0; i<2*n-1; i++){
int minn = INF,flag,k;   //得到新的最短路、此短路,并记下该点信息;
for (int j=0; j<n; j++){
if (!vis[j][0] && d[j][0] < minn){
minn = d[j][0];
flag = 0;
k = j;
}
else if (!vis[j][1] && d[j][1] < minn){
minn = d[j][1];
flag = 1;
k = j;
}
}
if (minn >= INF) break;
vis[k][flag] = 1;
for (int j = 0; j<G[k].size(); j++){      //更新与之相邻的节点信息(最短路,次短路)
Edge e = edges[G[k][j]];
if (d[e.to][0] > minn + e.dist){
d[e.to][1] = d[e.to][0];
cnt[e.to][1] = cnt[e.to][0];
d[e.to][0] = minn + e.dist;
cnt[e.to][0] = cnt[k][flag];
}
else if (d[e.to][0] == minn + e.dist){
cnt[e.to][0] += cnt[k][flag];
}
else if (d[e.to][1] > minn + e.dist){
d[e.to][1] = minn + e.dist;
cnt[e.to][1] = cnt[k][flag];
}
else if (d[e.to][1] == minn + e.dist){
cnt[e.to][1] += cnt[k][flag];
}
}
}
if (d[t][1] == d[t][0] + 1){
cnt[t][0] += cnt[t][1];
}
return cnt[t][0];
}

int main(){
int T,m;
scanf("%d",&T);
while (T--){
init();
scanf("%d%d",&n,&m);
int x,y,z;
for (int i=0; i<m; i++){
scanf("%d%d%d",&x,&y,&z);
x--;
y--;
addEdge(x,y,z);
}
int s,t;
scanf("%d%d",&s,&t);
s--;
t--;
printf("%d\n",dijkstra(s,t));
}
return 0;
}


求此短路的长度(每条边、每个节点可以走多次):

此短路如果存在,就一定会是最短路上某一条边不走,而走了其它边再回到最短路上;

求解思路:

分别对起点和终点求一次单源最短路ds[i],dt[i],枚举所有的边(u,v),求出ds[u] + dt[v] + dist[u][v] 大于最短路 中最小的一个值,即为此段路值。

poj3255 求此短路模板题;(此题与上题不同的地方在于每条边、每个节点可以走多次;)

#include<cstdio>
#include<cstring>
#include<cmath>
#include<cstdlib>
#include<climits>
#include<cctype>
#include<iostream>
#include<algorithm>
#include<queue>
#include<vector>
#include<map>
#include<set>
#include<string>
#include<stack>
#define ll long long
#define MAX 10000
#define MAXN 1000000
#define INF 100000000
#define eps 1e-8

using namespace std;

struct Edge{
int from ,to, dist;
};

struct Node{
int num,w;
bool operator < (const Node& rhs) const{
return rhs.w < w;
}
};

int first[MAX],next[MAXN];
vector<Edge>edges;

int n;

void init(){
memset(first,-1,sizeof(first));
memset(next,-1,sizeof(next));
edges.clear();
}

void addEdge(int from, int to, int dist){
edges.push_back((Edge){from,to,dist});
int k = edges.size();
next[k-1] = first[from];
first[from] = k-1;
}

int d[MAX][2];

void dijkstra(int s, int t, int flag){
int vis[MAX];
priority_queue<Node>q;
memset(vis,0,sizeof(vis));
for (int i=0; i<n; i++) d[i][flag] = (i == s ? 0 : INF);
q.push((Node){s,0});
while (!q.empty()){
Node temp = q.top();
q.pop();
int u = temp.num;
if (vis[u]) continue;
vis[u] = 1;
for (int i = first[u]; i != -1; i = next[i]){
Edge e = edges[i];
if (!vis[e.to]){
d[e.to][flag] = min(d[e.to][flag], d[u][flag] + e.dist);
q.push((Node){e.to,d[e.to][flag]});
}
}
}
}

int main(){
int m;
while (scanf("%d%d",&n,&m) != EOF){
int x,y,z;
init();
for (int i=0; i<m; i++){
scanf("%d%d%d",&x,&y,&z);
x--;
y--;
addEdge(x,y,z);
addEdge(y,x,z);
}
dijkstra(0,n-1,0);
dijkstra(n-1,0,1);
int ans = INF;
for (int i=0; i<edges.size(); i++){
int u = edges[i].from;
int v = edges[i].to;
if (d[u][0] + d[v][1] + edges[i].dist > d[n-1][0]){
ans = min(ans,d[u][0] + d[v][1] + edges[i].dist);
}
}
printf("%d\n",ans);
}
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: