#include <iostream>
using namespace std;
const int N=101;
const int M=501;
const int INF=501;// 道路编号作最大值
const int DIV=100000;
int g[N][N];
int path[N];
void init(int n)
{
for(int i=0;i<n;i++){
for(int j=0;j<n;j++)
{
g[i][j]=g[j][i]=INF;
}
}
}
void dijkstra(int s,int n)
{
int visit[n];
int len[n];
for(int i=0;i<n;i++)
{
visit[i]=0;
path[i]=s;// 初始值都是直接到达s点
len[i]=g[s][i];
}
visit[s]=1;
len[s]=0;
//path[s]=-1;
int min;
int k;
for(int i=1;i<n;i++)
{
min=INF;
k=-1;
for(int j=0;j<n;j++)
{
if(visit[j]==0&&len[j]<=min)
{
k=j;
min=len[j];
}
}
visit[k]=1;
for(int j=0;j<n;j++)
{
//int tmp=min+g[k][j];//
int tmp=g[k][j];
//
// 因为新加入的路径如果编号小,下一次再加入更小就说明符合DIJKSTRA
// 不需要计算路径之和 ,理由是:
// 2^K+2^(K+1)<2^(K+2)
if(visit[j]==0&&tmp<len[j])
{
len[j]=tmp;
path[j]=k;// 从S到达J的最短路径先经过K
}
}
}
}
int dis[M+1];
void initDis()
{
dis[0]=1;
for(int i=1;i<M;i++)
{
dis[i]=(dis[i-1]<<1)%DIV;
}
}
void func()
{
int n,m;
while(cin>>n>>m)
{
init(n);
initDis();
for(int i=0;i<m;i++)
{
int a,b;
cin>>a>>b;
g[a][b]=g[b][a]=i;// 记录的是道路编号,正好道路编号也是递增的,可以当距离来比较
}
dijkstra(0,n);
int sum=0;
for(int i=1;i<n;i++)
{
int k=i;// 当前要求0到K的最短距离
sum=0;
while(k!=0)
{
int last=path[k];//上一顶点
if(g[last][k]==INF)// 无法到达
{
sum=0;
break;
}
sum+=dis[g[last][k]];//加上这一段的距离
sum=sum%DIV;
k=last;// 计算下一段,直到遇到所求0号点
}
if(sum==0)
cout<<-1<<endl;
else
cout<<sum<<endl;
}
}
}
int main(int argc, char *argv[])
{
//printf("Hello, world\n");
func();
return 0;
}
dijkstra,特别之处在于道路长度是2^K,路径松弛计算加法时可能会溢出,只需要保存路径,然后依次模得到结果
-
题目描述:
-
N个城市,标号从0到N-1,M条道路,第K条道路(K从0开始)的长度为2^K,求编号为0的城市到其他城市的最短距离
-
输入:
-
第一行两个正整数N(2<=N<=100)M(M<=500),表示有N个城市,M条道路
接下来M行两个整数,表示相连的两个城市的编号
-
输出:
-
N-1行,表示0号城市到其他城市的最短路,如果无法到达,输出-1,数值太大的以MOD 100000 的结果输出。
-
样例输入:
-
4 4 1 2 2 3 1 3 0 1
-
样例输出:
-
8 9 11