题目http://acm.hdu.edu.cn/showproblem.php?pid=2544
模板题三种解题方法
dijkstra:
#include<cstdio>
#include<cstring>//memset
#include<algorithm>//min
#define INF 0x3f3f3f3f
#define maxn 110
using namespace std;//algorithm
int n,m,map[maxn][maxn],dis[maxn];//map[][]两点之间的距离 dis[]起始点(源点)到当前点的距离
bool visit[maxn];//判断该点是否被访问
void dijkstra(int s)
{
int next;//下一个进入(最短距离) V集合的点
memset(visit,0,sizeof(visit));// 一开始 V集合中无任何元素
// memset(map,INF,sizeof(map));
for(int i=1;i<=n;i++)//dis初始化 起始点(源点)到当前点的距离
dis[i]=map[s][i];
visit[s]=true;//将源点放入集合V
dis[s]=0;//源点到源点的距离为0
for(int i=1;i<n;i++)//已经把U集合中的一个点存入V集合 最多进行n-1次寻找最小值
{
int temp=INF;// 一开始默认两点之间的距离为INF
for(int u=1;u<=n;u++)
{
if(!visit[u]&&dis[u]<temp)//找最小值(该点不在V集合 并且 该点到源点的距离小于 当前值 )
{
temp=dis[u];
next=u;
}
}
visit[next]=true;//将离源点最近的点存入V集合
for(int u=1;u<=n;u++)//松弛
{
if(!visit[u])
dis[u]=min(dis[u],dis[next]+map[next][u]);
}
}
}
int main()
{
int a,b,c;
while(scanf("%d%d",&n,&m),n,m)
{
memset(map,INF,sizeof(map));// 不能在dijkstra()中初始化 对map[][]赋值前初始化
while(m--)
{
scanf("%d%d%d",&a,&b,&c);
if(map[a][b]>c)//避免重复 上面初始化为INF map仍为INF表示未走过这条路
map[a][b]=map[b][a]=c;
}
dijkstra(1);
printf("%d\n",dis[n]);
}
return 0;
}
spfa:
#include<cstdio>
#include<cstring>
#include<queue>
#define INF 0x3f3f3f3f
#define MAXN 100+10//点数
#define MAXM 20000+10//边数
using namespace std;
int n,m,top,vis[MAXN],dis[MAXN],visit[MAXN],head[MAXN];
struct node {
int from,to,val,next;
};
node edge[MAXM];
void init()//初始化邻接表
{
top=0;//建表从零开始
memset(head,-1,sizeof(head));
}
void add(int u,int v,int w)//建立邻接表
{
edge[top].from=u;
edge[top].to=v;
edge[top].val=w;
edge[top].next=head[u];
head[u]=top++;
}
void spfa(int s)//s为源点
{
queue<int>q;//存储每次入队的点
memset(vis,0,sizeof(vis));
memset(dis,INF,sizeof(dis));//存储源点 到这个点的最短路
vis[s]=1;//表示这个点是否在队列里面
dis[s]=0;
q.push(s);
while(!q.empty())
{
int u=q.front();
q.pop();
vis[u]=0;//该点之后还可能进入队列 消除标记
for(int i=head[u];i!=-1;i=edge[i].next)//遍历以u为起点的 所有边
{
int v=edge[i].to;
if(dis[v]>dis[u]+edge[i].val)
{
dis[v]=dis[u]+edge[i].val;\
if(!vis[v])
{
q.push(v);
vis[v]=1;
}
}
}
}
printf("%d\n",dis[n]);
}
void getmap()
{
while(m--)
{
int a,b,c;
scanf("%d%d%d",&a,&b,&c);
add(a,b,c);
add(b,a,c);//无向图 既可由a->b,也可由b->a;
}
}
int main()
{
while(scanf("%d%d",&n,&m),n|m)//n|m位运算符 n==0&&m==0时输入结束
{
init();
getmap();
spfa(1);
}
return 0;
}
floyd:
#include<stdio.h>
#define INF 0x3f3f3f3f
int n,m,path[110][110];
void init()
{
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
{
if(i==j)
path[i][j]=0;
else path[i][j]=INF;
}
}
void floyd()
{
int i,j,k;
for(k=1;k<=n;k++)//K是穷举i,j的断点 必须是最外层表示断点
for(i=1;i<=n;i++)
for(j=1;j<=n;j++)
{
if(path[i][j]>path[i][k]+path[k][j])
path[i][j]=path[i][k]+path[k][j];
}
}
void getmap()
{
int a,b,c;
while(m--)
{
scanf("%d%d%d",&a,&b,&c);
if(path[a][b]>c)//防止重复 一开始初始化为INF 若已经选过 则不满足if
path[a][b]=path[b][a]=c;
}
}
int main()
{
while(scanf("%d%d",&n,&m),n|m)
{
init();
getmap();
floyd();
printf("%d\n",path[1][n]);
}
return 0;
}