您的位置:首页 > 其它

URAL1004 Sightseeing Trip Floyd 最小环

2015-12-14 05:43 411 查看
题意:求有权无向图的最小环,环至少包括三个点。

思路:

设map[i,j]表示i到j的的距离。输入有重边,在处理输入的时候只保存最短边。

取环中一个点k,左右点是ij则map[i,k]和map[k,j]是固定的不能变,可改变的是没有加入k点的i,j之间的最短路,设为dist[i,j]。那么最短环的长度表示为dist[i,j]+map[i,k]+map[k,j]。

Floyd的最外层循环为k时,最短路还没有用k和更新ij之间的最短路,恰好符合要求。所以在还没有用k更新ij之间的最短路之前更新环,每次更新环时更新路径即可。

算法步骤:

输入输出Floyd算法的框架,三个循环,在更新路径前更新环的最短路径。题解一和其他的题解(都是DP)代码很短,步骤很清晰,所以算法步骤粗略写写。

算法复杂度:

输入输出两个循环不超过O(n2),时间主要消耗在Floyd算法的框架里,三个n次循环,所以时间复杂度O(n3),最多是二维数组,空间复杂度是O(n2)

代码:

const int maxn=110;
int dist[maxn][maxn], map[maxn][maxn]; //最短距离,原图
int pre[maxn][maxn]; // pre[i,j]记录最短路里,j前面一个点
int path[maxn];      // 答案路径
int n, m, num, minc; // num记录path里有多少个点,minc是最短环长度

int main()
{
int  u, v, cost;
while(cin >> n && n){
if(n<0) break;
cin >> m;
for(int i=1; i<=n; i++){
for(int j=1; j<=n; j++){
dist[i][j]=map[i][j]=INF;
pre[i][j]=i;
}
}
for(int i=1; i<=m; i++){
scanf("%d %d %d",&u,&v,&cost);
if(dist[u][v]>cost)   //重边
map[u][v]=map[v][u]=dist[u][v]=dist[v][u]=cost;
}
// floyd
minc=INF;
for(int k=1; k<=n; k++){
// k还没加入(i,j)最短路,更新最短环
for(int i=1; i<k; i++){
for(int j=i+1; j<k; j++){
int  ans=dist[i][j]+map[i][k]+map[k][j];
if(ans<minc){  //找到最优解
minc=ans;
num=0;
int p=j;
while(p!=i){  //逆向寻找前驱遍历的路径并将其存储起来
path[num++]=p;
p=pre[i][p];
}
path[num++]=i;
path[num++]=k;
}
}
}
//用k更新i到j的最短路径
for(int i=1; i<=n; i++){
for(int j=1; j<=n; j++){
if(dist[i][j]>dist[i][k]+dist[k][j]){
dist[i][j]=dist[i][k]+dist[k][j];
pre[i][j]=pre[k][j];
}
}
}
}// end Floyd
if(minc==INF) puts("No solution.");
else{
printf("%d",path[0]);
for(int i=1; i<num; i++)
printf(" %d",path[i]);
puts("");
}
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: