次短路问题

求最短路和次短路的数量(次短路严格大于最短路):

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);
	}
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值