|
1 定义: 通常来说最小环是针对有向图而言 从一个点出发,经过一条简单路径回到起点成为环.图的最小环就是所有环中长度最小的. 2.怎样求最小环呢? 1传统的解决方法(dijkstra): 2.floyd求最小环: 抛开Dijkstra算法,进而我们想到用Floyd算法。我们知道,Floyd算法在进行时会不断更新矩阵dist(k)。设dist[k,i,j]表示从结点i到结点j且满足所有中间结点,它们均属于集合{1,2,⋯ ,k}的一条最短路径的权。其中dist[0,i,j ]即为初始状态i到j的直接距离。对于一个给定的赋权有向图, 求出其中权值和最小的一个环。我们可以将任意一个环化成如下形式:u->k->v ->(x1-> x2-> ⋯ xm1)-> u(u与k、k与v都是直接相连的),其中v ->(x1-> 2-> ⋯ m)-> u是指v到u不经过k的一种路径。 在u,k,v确定的情况下,要使环权值最小, 则要求 (x1一>x2->⋯一>xm)->u路径权值最小.即要求其为v到u不经过k的最短路径,则这个经过u,k,v的环的最短路径就是:[v到u不包含k的最短距离]+dist[O,u,k]+dist[O,k,v]。我们用Floyd只能求出任意2点间满足中间结点均属于集合{1,2,⋯
,k}的最短路径,可是我们如何求出v到u不包含k的最短距离呢? |
Floyd求两点间最短路
//Floyd-Warshall算法核心语句
for(k=1;k<=n;k++)
for(i=1;i<=n;i++)
for(j=1;j<=n;j++)
if(e[i][k]<inf && e[k][j]<inf && e[i][j]>e[i][k]+e[k][j])
e[i][j]=e[i][k]+e[k][j]; http://acm.fzu.edu.cn/problem.php?pid=2090
#include<stdio.h>
#include<string.h>
#define M 107
#define inf 0x3f3f3f
using namespace std;
int g[M][M],dis[M][M],path[M][M],pre[M];
int n,m,num,mincircle,count;
void init()
{
for(int i=1; i<=n; i++)
{
for(int j=1; j<=n; j++)
{
g[i][j]=dis[i][j]=inf;
}
g[i][i]=dis[i][i]=0;
}
}
void dfs(int i,int j)
{
int k=path[i][j];
if(k==0)
{
pre[num++]=j;
return ;
}
dfs(i,k);
dfs(k,j);
}
void Floyd()
{
mincircle=inf;
for(int k=1; k<=n; k++)
{
for(int i=1; i<k; i++)//求环
for(int j=i+1; j<k; j++)
{
if(mincircle>dis[i][j]+g[i][k]+g[k][j])
{
mincircle=dis[i][j]+g[i][k]+g[k][j];
num=0;
pre[num++]=i;
dfs(i,j);
pre[num++]=k;
count=1;
}
else if(mincircle==dis[i][j]+g[i][k]+g[k][j])//记录次数
count++;
}
for(int i=1; i<=n; i++)//求最短路
for(int j=1; j<=n; j++)
if(dis[i][k]+dis[k][j]<dis[i][j])
{
dis[i][j]=dis[i][k]+dis[k][j];
path[i][j]=k;
}
}
}
int main()
{
int t;
scanf("%d",&t);
while(t--)
{
scanf("%d%d",&n,&m);
init();
int a,b,c;
for(int i=1; i<=m; i++)
{
scanf("%d%d%d",&a,&b,&c);
if(g[a][b]>c)
{
g[a][b]=g[b][a]=c;
dis[a][b]=dis[b][a]=c;
}
}
memset(path,0,sizeof(path));
Floyd();
if(mincircle==inf)
printf("-1\n");
else
printf("%d %d\n",mincircle,count);
}
return 0;
}http://poj.org/problem?id=1734
题意:求一个图中最小环,输出路径。
#include <iostream>
#include <string.h>
#include <stdio.h>
using namespace std;
const int N=105;
const int INF=9999999;
int map[N][N],dist[N][N];
int road[N][N],path[N];
int m,n,cnt,ans;
void Init()
{
for(int i=1;i<=n;i++)
{
for(int j=1;j<=n;j++)
{
dist[i][j]=INF;
road[i][j]=0;
}
}
}
/**记录最小环的路径*/
void Record(int s,int t)
{
if(road[s][t])
{
Record(s,road[s][t]);
Record(road[s][t],t);
}
else path[cnt++]=t;
}
void Floyd()
{
int i,j,k;
ans=INF;
for(k=1;k<=n;k++)
{
/**最小负环的判定*/
for(i=1;i<k;i++)
{
for(j=i+1;j<k;j++)
{
if(ans>dist[i][j]+map[i][k]+map[k][j])
{
ans=dist[i][j]+map[i][k]+map[k][j];
cnt=0;
path[cnt++]=i;
Record(i,j);
path[cnt++]=k;
}
}
}
/**正常floyd部分*/
for(i=1;i<=n;i++)
{
for(j=1;j<=n;j++)
{
if(dist[i][j]>dist[i][k]+dist[k][j])
{
dist[i][j]=dist[i][k]+dist[k][j];
road[i][j]=k;
}
}
}
}
}
int main()
{
int i,j,u,v,w;
while(cin>>n>>m)
{
Init();
while(m--)
{
cin>>u>>v>>w;
if(w<dist[u][v]) /**如果有重边,就取最小的权值*/
{
dist[u][v]=w;
dist[v][u]=w;
}
}
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
map[i][j]=dist[i][j];
Floyd();
if(ans==INF) puts("No solution.");
else
{
cout<<path[0];
for(int i=1;i<cnt;i++)
cout<<" "<<path[i];
cout<<endl;
}
}
return 0;
}
2126

被折叠的 条评论
为什么被折叠?



