畅通工程续 Time Limit: 3000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others) Total Submission(s): 50050 Accepted Submission(s): 18646
Problem Description
某省自从实行了很多年的畅通工程计划后,终于修建了很多路。不过路多了也不好,每次要从一个城镇到另一个城镇时,都有许多种道路方案可以选择,而某些方案要比另一些方案行走的距离要短很多。这让行人很困扰。
现在,已知起点和终点,请你计算出要从起点到终点,最短需要行走多少距离。
Input
本题目包含多组数据,请处理到文件结束。
每组数据第一行包含两个正整数N和M(0<N<200,0<M<1000),分别代表现有城镇的数目和已修建的道路的数目。城镇分别以0~N-1编号。
接下来是M行道路信息。每一行有三个整数A,B,X(0<=A,B<N,A!=B,0<X<10000),表示城镇A和城镇B之间有一条长度为X的双向道路。
再接下一行有两个整数S,T(0<=S,T<N),分别代表起点和终点。
Output
对于每组数据,请在一行里输出最短需要行走的距离。如果不存在从S到T的路线,就输出-1.
Sample Input
3 3
0 1 1
0 2 3
1 2 1
0 2
3 1
0 1 1
1 2
Sample Output
Author
linle
Source
Recommend
lcy | We have carefully selected several similar problems for you:
2066
2112
1217
1875
1233
#include<iostream>
#include<math.h>
#include<memory.h>
using namespace std;
#define inf 0x3f3f3f3f
int n,m;//n现有城镇数目,m道路数目
int map[300][300];
int dis[300],vis[300];
void dijkstra(int a,int b)
{
int i,j,k,minn;
for(i=0;i<n;i++)
{
dis[i]=map[a][i];
vis[i]=0;
}
vis[a]=1;
for(i=0;i<n;i++)
{
minn=inf;
for(j=0;j<n;j++)
{
if(vis[j]==0&&dis[j]<minn)
{
k=j;
minn=dis[j];
}
}
vis[k]=1;
for(j=0;j<n;j++)
{
if(vis[j]==0&&dis[j]>dis[k]+map[k][j])
{
dis[j]=dis[k]+map[k][j];
}
}
}
if(dis[b]<inf)
printf("%d\n",dis[b]);
else
printf("-1\n");
}
int main()
{
while(scanf("%d%d",&n,&m)!=EOF)
{
int a,b,x,s,e;
memset(map,inf,sizeof(map));
for(int i=0;i<m;i++)
{
cin>>a>>b>>x;
if(map[a][b]>x)//城镇之间道路不止一条
map[a][b]=map[b][a]=x;
}
cin>>s>>e;
if(s==e)//起点和终点一样
cout<<0<<endl;
else
dijkstra(s,e);
}
}
SFPA
#include <iostream>
#include<memory.h>
using namespace std;
int a[201][201], b[201][201],dis[201];
int n, m, s, t;
void spfa(int s)//求单源点s到其它各顶点的最短距离
{
bool vis[201];
int q[10001];
for(int i=0; i<=n; i++)//初始化每点到S的距离,不在队列
dis[i]=99999999;
dis[s]=0;//将dis[源点]设为0
vis[s]=true;//源点S入队列
q[1]=s; // 队列的初始状态,s为起点
int i, v, head=0, tail=1;//头尾指针赋初值
while (head<tail) //队列不空
{
head++;
v=q[head]; // 取队首元素
vis[v]=0; // 释放结点,一定要释放掉,因为这节点有可能下次用来松弛其它节点
for(i=1; i<=b[v][0]; i++)//对于与对首v相连的每一条边
if (dis[b[v][i]] > dis[v]+a[v][b[v][i]])//如果不满足三角形性质/
{
dis[b[v][i]] = dis[v]+a[v][b[v][i]]; //松弛 dis[i]
if (vis[b[v][i]]==0) // 不在队列则加入队列
{
tail++;
q[tail]=b[v][i];
vis[b[v][i]]=1;
}
}
}
}
int main()
{
int x, y, z;
while(cin >> n >> m)//n结点数;m边数
{
memset(a,0,sizeof(a));
memset(b,0,sizeof(b));
for(int i=0; i<m; i++)
{
cin >> x >> y >> z; // x,y一条边的两个结点;z这条边的权值
if (a[x][y]!=0 && z>a[x][y])
continue;//如果两顶点间有多条边,保留最小的一条
b[x][0]++;//b[x,0];//以x为一个结点的边的条数
b[y][0]++;
b[x][b[x][0]]=y;
b[y][b[y][0]]=x;
a[x][y]=a[y][x]=z;
}
cin >> s >> t; // 读入起点与终点
memset(dis,0,sizeof(dis));
spfa(s);
// cout<<dis[t]<<endl;
if (dis[t]!=99999999) cout << dis[t] << endl;
else cout << -1 << endl;
}
return 0;
}
SFPA+SFPA前向星优化
#include <iostream>
#include<memory.h>
#include<queue>
using namespace std;
struct edge
{
int point,next,len;
} e[10005];
int n, m, s, t;
int dis[202],vis[202],first[5001];
void add(int i, int u, int v, int w)
{
e[i].point = v;
e[i].next = first[u];
e[i].len = w;
first[u] = i;
}
void spfa(int s)
{
int i, v, head=0, tail=1;
memset(dis,0,sizeof(dis));
memset(vis,0,sizeof(vis));
queue<int>q;
for(i=0; i<=n; i++)
dis[i]=99999999;
dis[s]=0;
vis[s]=1;
q.push(s);
while (!q.empty()) //队列不空
{
int v=q.front(); //取队首元素
q.pop();
vis[v]=0; //释放结点,一定要释放掉,因为这节点有可能下次用来松弛其它节点
for (int j = first[v]; j; j = e[j].next) //这就是遍历边了
{
if(dis[e[j].point]>dis[v]+e[j].len)
{
dis[e[j].point]=dis[v]+e[j].len;
if(vis[e[j].point]==0)
{
q.push(e[j].point);
vis[e[j].point]=1;
}
}
}
}
}
int main()
{
int u,v,w;
while(cin >> n >> m)
{
int cnt=1;
memset(first,0,sizeof(first));
for (int i = 1; i <= m; i++)
{
cin >> u >> v >> w;
add(cnt++,u,v,w);
add(cnt++,v,u,w);
} //这段是读入和加入
cin >> s >> t; //读入起点与终点
spfa(s);
if (dis[t]!=99999999) cout << dis[t] << endl;
else cout << -1 << endl;
}
return 0;
}
|