您的位置:首页 > 编程语言 > C语言/C++

【训练题】单源最优路径 SPFA(队列优化)算法

2016-07-16 16:23 429 查看
【问题描述】

给出N个顶点,M条无向带权边的连通图,和一个出发点(源点)S:请编程计算:

问1、S到其他点的所有路径中,需要经过的最小边最大的那条路径(最小边最大);

问2、S到其他点的所有路径中,需要经过的最大边最小的那条路径(最大边最小);

【输入格式】

第一行:N(N<=50,000),M(M<=100,000),为图的顶点数目和边的数目。

接下来m行,每行三个整数x,y,t,为一条边关联的两个顶点和边的权值。

最后一行一个整数S。

【输出格式】

共N-1行,每行2个整数,第i行的两个整数分别表示从S到顶点i(i!=s)的最小边的最大值,最大边的最小值。

【输入样例】

6 10
1 2 4
1 3 8
2 3 3
2 4 4
2 5 6
3 4 2
3 5 2
4 5 4
4 6 9
5 6 4
1


【输出样例】

4 4
8 4
4 4
4 4
4 4


【数据范围】

N<=50,000

M<=100,000

思路:

方法一:最优生成树算法

先生成最大生成树(无根树),然后将s定为这棵树的根,那么在树上,任意一点到s的路径上经过的最大边就是“s到该点的最小边的最大值”。

同理,用最小生成树,可以计算“s到该点的最大边的最小值”。

方法二:SPFA算法(最近在学最优路径,因此用该法完成)

第(1)问中用dist[i]表示s到i的所有路径中,最小边最大的那条路径中的最小边的权值。

第(2)问中用dist[i]表示s到i的所有路径中,最大边最小的那条路径中的最大边的权值。

/*
Name: SPFA
Copyright: Twitter & Instagram @stevebieberjr
Author: @stevebieberjr
Date: 16-07-16 16:42
*/
#include<cstdio>
#include<vector>
#include<cstring>
#include<queue>
#include<algorithm>
#define maxn 50005
#define inf 1000000000
using namespace std;

//dist[i]:s到i的所有路径中,最小边最大的那条路径中的最小边的权值
//dist1[i]:s到i的所有路径中,最大边最小的那条路径中的最大边的权值
int n,m,s,dist[maxn],dist1[maxn];
vector<int>g[maxn],w[maxn];
bool inq[maxn];

void SPFA(int s,int *d)
{
queue<int>q;
for(int i=1;i<=n;i++)
{
d[i]=-inf; //求最小边最大,将初值赋为-inf
}
memset(inq,0,sizeof(inq));
q.push(s); //s入队列
inq[s]=1;
d[s]=inf; //最开始认为s不能到s,所以最小边的最大值为inf

while(!q.empty())
{
int i=q.front(); q.pop();
inq[i]=0;
for(int k=0;k<g[i].size();k++)
{
int j=g[i][k],c=w[i][k];
int tmp=min(c,d[i]); //tmp为s->j的路径上的最小边
if(tmp>d[j]) //最小边取最大值
{
d[j]=tmp;
if(inq[j]) continue;
q.push(j);
inq[j]=1;
}
}
}
}

void SPFA1(int s,int *d) //与第(1)问相反
{
queue<int>q;
for(int i=1;i<=n;i++)
{
d[i]=inf;
}
memset(inq,0,sizeof(inq));
q.push(s);
inq[s]=1;
d[s]=-inf;

while(!q.empty())
{
int i=q.front(); q.pop();
inq[i]=0;
for(int k=0;k<g[i].size();k++)
{
int j=g[i][k],c=w[i][k];
int tmp=max(c,d[i]);
if(tmp<d[j])
{
d[j]=tmp;
if(inq[j]) continue;
q.push(j);
inq[j]=1;
}
}
}
}

int main()
{
//freopen("in.txt","r",stdin);
//freopen("out.txt","w",stdout);
scanf("%d%d",&n,&m);
int x,y,t;
for(int i=1;i<=m;i++)
{
scanf("%d%d%d",&x,&y,&t);
g[x].push_back(y);
g[y].push_back(x);
w[x].push_back(t);
w[y].push_back(t);
} //建立图的存储结构
scanf("%d",&s);
SPFA(s,dist);
SPFA1(s,dist1);
for(int i=1;i<=n;i++)
{
if(i!=s) printf("%d %d\n",dist[i],dist1[i]);
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  优化 算法 编程 队列 c++