这题道是有关
最短路裸题。一开始在求最短集合里面到外集合的最短路径的时候,把vis[i]写成了vis[j]。让程序一直都出错。
思路:(
Dijkstra 算法)
从单源点st开始,在外集合当中寻找离最短路集合最近的在外集合当中的点 i 。逐层往外延伸,延伸的同时需要不断更新从st到外集合 j 点距离dis[j].如果从最短集合里面经过 i 点再到 j 点的距离比原来的dis[j]还要近的话,那就更新dis[ j ]。该算法的时间复杂度是(n^2),空间复杂度为(n^2)
代码:
#include<iostream>
using namespace std;
#define MDIS 1000000
int dis[110],map[110][110],vis[110];//map[i][j]表示从i点到j点的距离。若两点间无通路,则距离为无穷大,vis[i]则表示i点是否已经在最短集合当中,dis[i]表示i 点到源点的最短距离
int main()
{
int n,m,min,i,j,v,a,b,c;
while(scanf("%d%d",&n,&m)!=EOF&&!(n==0&&m==0))
{
for(i=1;i<=n;i++)
for(j=1;j<=n;j++) map[i][j]=MDIS;
for(i=0;i!=m;i++)
{
scanf("%d%d%d",&a,&b,&c);
map[a][b]=c;
map[b][a]=c;
}
memset(vis,0,sizeof(vis));
vis[1]=1;
for(i=1;i<=n;i++) dis[i]=map[1][i];
for(i=1;i<n;i++)
{
//cout<<"good"<<endl;
min=MDIS;
for(j=1;j<=n;j++)
{
//cout<<"good"<<endl;
if(!vis[j]&&min>dis[j])//这里应该是j这个点没有放入最短集合当中
{
min=dis[j];
v=j;
}
}
vis[v]=1;
for(j=1;j<=n;j++)
{
//cout<<"good"<<endl;
if(!vis[j]&&dis[v]+map[v][j]<dis[j]) dis[j]=dis[v]+map[v][j];
}
}
printf("%d\n",dis[n]);
}
return 0;
}
思路:(floyd-warshall 算法)如果用这个算法做这题的话,那样这就和传递闭包的问题一样。通过找出 i 点与 j 点间的最短距离来得出出发点与目标点的最短距离。而在这个过程中,需要列举 i 点及 j 点间的所有可能的中间点。当找到一个中间点 k 使,map[i][j] > map[i][k]+map[k][j]。这时更新map[i] [j]。同时,在初使化的时候应当将所的点间的距离初使化为无穷大。这个算法的时间复杂度是(n^3)比上面的算法慢。不过这个算法写得来短得多。
代码:
#include<iostream>
#define MDIS 1000000
using namespace std;
int map[110][110];
int main()
{
int a,b,c,m,n,i,j,k;
while(scanf("%d%d",&n,&m)!=EOF&&!(n==0&&m==0))
{
for(i=1;i<=n;i++)
for(j=1;j<=n;j++) map[i][j]=MDIS;
for(i=0;i!=m;i++)
{
scanf("%d%d%d",&a,&b,&c);
map[a][b]=c;//这个要这样将a和b互换而且同时赋矛c是因为题目给的那路径并没有一个规定的顺序例如:map[3][1]=map[3][2]+map[2][1]不成立,,假如换回来map[1][3][=map[1][2]+map[2][3];这样也不可以保证正确性。
map[b][a]=c;
}
for(k=1;k<=n;k++)
for(i=1;i<=n;i++)
for(j=1;j<=n;j++)
{
if(map[i][j]>map[i][k]+map[k][j])
map[i][j]=map[i][k]+map[k][j];
}
printf("%d\n",map[1][n]);
}
return 0;
}
思路:(BF算法)这个算法确实不怎样,效率比较低,不过自己对这个算法的实现也不太明白。不清楚为什么一定要用结构体。这里的核心代码是一个二重循环,外疏层循环是一个n-1次(n为图中点的个数)。这里面为什么最多是n-1次呢,我想是因为当要得到一个最短路径,途经的边最多为n-1个。因为有环的情况都可以排除。通过不断地松驰达到求最短路径。这个算法的效率为(VE)。
#include<iostream>
using namespace std;
#define MDIS 100000
struct path
{
int s,e,c;
}pa[10005];
int d[110];
int main()
{
int n,m,i,j,a,b,c;
while(scanf("%d%d",&n,&m)!=EOF&&!(n==0&&m==0))
{
for(i=0;i!=m;i++)
{
scanf("%d%d%d",&a,&b,&c);
pa[i].s=a,pa[i].e=b,pa[i].c=c;
}
for(i=0;i!=110;i++) d[i]=MDIS;
d[1]=0;
for(i=0;i<n-1;i++)
{
for(j=0;j<m;j++)
{
if(d[pa[j].s]+pa[j].c<d[pa[j].e]) d[pa[j].e]=d[pa[j].s]+pa[j].c;
if(d[pa[j].e]+pa[j].c<d[pa[j].s]) d[pa[j].s]=d[pa[j].e]+pa[j].c;
}
}
printf("%d\n",d[n]);
}
return 0;
}
(二维数组实现):效率比用结构体实现更慢。而且感觉像是在用floyd算法。
代码:
#include<iostream>
#define MDIS 1000000
using namespace std;
int map[110][110],bst[110];
int main()
{
int i,j,m,n,a,b,c;
while(scanf("%d%d",&n,&m)!=EOF&&!(n==0&&m==0))
{
for(i=0;i!=110;i++)
{
bst[i]=MDIS;
for(j=0;j!=110;j++) map[i][j]=MDIS;
}
bst[1]=0;
//bst[0]=0;
for(i=0;i!=m;i++)
{
scanf("%d%d%d",&a,&b,&c);
map[a][b]=c;
map[b][a]=c;
}
// cout<<map[1][2]<<endl;
for(i=0;i<n-1;i++)
{
for(j=1;j<=n;j++)
{
for(int k=1;k<=n;k++)
{
if(map[j][k]!=MDIS)
{
if(bst[j]>bst[k]+map[k][j])
bst[j]=bst[k]+map[k][j];
if(bst[k]>bst[j]+map[k][j])
bst[k]=bst[j]+map[k][j];
}
}
}
}
printf("%d\n",bst[n]);
}
return 0;
}
SPFA算法:
代码:
#include<iostream>
#define MDIS 1000000
using namespace std;
int bst[110],map[110][110],queue[100*110],m,n;
bool vis[110];
void SPFA(void)
{
int u;
int front=0,rear=1;
queue[0]=1;
bst[1]=0;
vis[1]=true;
while(front<rear)
{
u=queue[front++];
vis[u]=false;
for(int i=1;i<=n;i++)
{
if(bst[i]>bst[u]+map[u][i])
{
bst[i]=bst[u]+map[u][i];
if(!vis[i])
{
queue[rear++]=i;
vis[i]=true;
}
}
}
}
}
int main()
{
int a,b,c;
while(scanf("%d%d",&n,&m)!=EOF&&!(n==0&&m==0))
{
for(int i=0;i<=n;i++)
{
bst[i]=MDIS;
vis[i]=false;
for(int j=0;j<=n;j++)
{
map[i][j]=MDIS;
}
}
// for(int i=1;i<=n;i++) bst[i]=map[0][i];
for(int i=0;i!=m;i++)
{
scanf("%d%d%d",&a,&b,&c);
map[a][b]=c;
map[b][a]=c;
}
SPFA();
printf("%d\n",bst[n]);
}
return 0;
}
dij + heap优化:这里要类比无优化的dij算法。heap的作用是让我们在查找最短的dis[ i ]的时候,效率提升为logn.不过因为,这个题的数据太小(只有100),所以不能很好地体现heap优化的效用
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <vector>
#include <queue>
#define N 110
#define inf 99999999
using namespace std;
int map[N][N],dis[N];
bool vis[N];
struct node
{
int u,dist;
bool operator<(const node &a) const
{
return dist > a.dist;
}
};
node temp;
priority_queue<node> Q;
vector<int> g[N];
int n;
void dij ()
{
temp.u = 1;
temp.dist = 0;
while (!Q.empty()) Q.pop();
Q.push(temp);
for (int i = 1;i <= n;i ++)
{
dis[i] = inf;
vis[i] = false;
}
dis[1] = 0;
while (!Q.empty())
{
int u = Q.top().u;
Q.pop();
if (vis[u]) continue;
vis[u] = true;
int len = g[u].size();
if (u == n) break;
for (int i = 0;i != len;i ++)
{
int j = g[u][i];
if ( !vis[j] && dis[j] > dis[u] + map[u][j])
{
dis[j] = dis[u] + map[u][j];
temp.u = j;
temp.dist = dis[j];
Q.push(temp);
}
}
}
printf ("%d\n",dis[n]);
}
int main ()
{
int m,x,y,c;
while (~scanf("%d%d",&n,&m))
{
if (n ==0 && m == 0) break;
for (int i = 1;i <= n;i ++)
for (int j = 1;j <= n;j ++) map[i][j] = inf;
for (int i = 1;i <= n;i ++)
{
g[i].clear();
map[i][i] = 0;
}
for (int i = 0;i != m;i ++)
{
scanf("%d%d%d",&x,&y,&c);
if (map[x][y] < inf)
{
map[x][y] = map[y][x] = min(map[x][y],c);
}
else
{
map[x][y] = map[y][x] = c;
g[x].push_back(y);
g[y].push_back(x);
}
}
dij();
}
return 0;
}