这题很好的综合了图论和数论的知识来解题,这种转化综合的思维我要好好地加强训练才行……其实这里明白到一点就可以很好地知道它们之间是怎么转化的,当map[i][j]表示i到j的最短路径,map[j][k]表示j到k的最短路径,且是经过n条路时,那么i到k的最短距离且经过2*n条路就一定是map[i][j]+map[j][k]了!
#include<iostream>
#include<cstring>
#include<cstdio>
using namespace std;
#define inf 1000000000
#define N 205
int n,num,map[N][N],dis[N][N]; //dis[i][j]表示从i到j经过k条路的最短距离
void slove()
{
while(n)
{
int ans[num][num];
if(n&1)
{
for(int i=0;i<num;i++)
{
for(int j=0;j<num;j++)
{
ans[i][j]=inf;
}
}
for(int i=0;i<num;i++)
{
for(int j=0;j<num;j++)
{
for(int k=0;k<num;k++)
{
ans[i][k]=min(ans[i][k],dis[i][j]+map[j][k]);
}
}
}
for(int i=0;i<num;i++)
{
for(int j=0;j<num;j++)
{
dis[i][j]=ans[i][j];
}
}
}
for(int i=0;i<num;i++)
{
for(int j=0;j<num;j++)
{
ans[i][j]=inf;
}
}
for(int i=0;i<num;i++)
{
for(int j=0;j<num;j++)
{
for(int k=0;k<num;k++)
{
ans[i][k]=min(ans[i][k],map[i][j]+map[j][k]);
}
}
}
for(int i=0;i<num;i++)
{
for(int j=0;j<num;j++)
{
map[i][j]=ans[i][j];
}
}
n>>=1;
}
}
int main()
{
//freopen("a.txt","r",stdin);
int t,s,e;
while(scanf("%d%d%d%d",&n,&t,&s,&e)!=EOF)
{
int vis[5*N];
memset(vis,-1,sizeof(vis));
for(int i=0;i<N;i++)
{
for(int j=0;j<N;j++)
{
map[i][j]=dis[i][j]=inf;
dis[i][i]=0;
}
}
num=0;
while(t--)
{
int l,x,y;
scanf("%d%d%d",&l,&x,&y);
if(vis[x]==-1)vis[x]=num++; //连续化节点编号
if(vis[y]==-1)vis[y]=num++;
map[vis[x]][vis[y]]=map[vis[y]][vis[x]]=l;
}
slove();
printf("%d\n",dis[vis[s]][vis[e]]);
}
return 0;
}