SSL-ZYC 1763 观光旅游
题目大意:
求一个图的最小环。
思路:
完全模板题。
思路一:直接用弗洛伊德,再加上一个判断是否有环的语句就可以了。
思路二:用dij,枚举每条边,将该边删除,再求该边的两个端点之间的最短路,最短路再加上这条边,就是一个环。
代码:
弗洛伊德:
#include <cstdio>
#include <iostream>
using namespace std;
const int maxn=99999999;
int a[101][101],n,m,b[101][101],ans,x,y,o;
int main()
{
scanf("%d%d",&n,&m);
for (int i=1;i<=n;i++)
for (int j=1;j<=n;j++)
a[i][j]=b[i][j]=maxn; //初始化
for (int i=1;i<=m;i++)
{
scanf("%d%d",&x,&y);
scanf("%d",&o);
a[x][y]=a[y][x]=b[x][y]=b[y][x]=o; //无向图
}
ans=99999999;
for (int k=1;k<=n;k++)
{
for (int i=1;i<=n;i++)
for (int j=1;j<=n;j++)
if(i!=j&&j!=k&&i!=k) ans=min(ans,b[i][j]+a[j][k]+a[k][i]); //求最小环
for (int i=1;i<=n;i++)
for (int j=1;j<=n;j++)
b[i][j]=min(b[i][j],b[i][k]+b[k][j]); //弗洛伊德
}
if (ans!=99999999) printf("%d\n",ans);
else printf("No solution\n");
return 0;
}
dij:
#include <cstdio>
#include <iostream>
#include <cstring>
using namespace std;
const int maxn=99999999;
int x[10001],y[10001],a[101][101],b[101],c[101];
int m,n,l,minn,o,ans;
int main()
{
scanf("%d%d",&n,&m);
ans=2147483647;
for (int i=1;i<=n;i++)
for (int j=1;j<=n;j++)
a[i][j]=maxn; //初始化
for (int i=1;i<=m;i++)
{
scanf("%d%d",&x[i],&y[i]);
scanf("%d",&a[x[i]][y[i]]);
a[y[i]][x[i]]=a[x[i]][y[i]];
}
for (int k=1;k<=m;k++)
{
l=a[x[k]][y[k]];
a[x[k]][y[k]]=maxn; //删边
memset(b,0,sizeof(b));
b[x[k]]=1;
for (int i=1;i<=n;i++)
if (i!=x[k]) c[i]=a[x[k]][i]; //dij初始化
for (int i=1;i<n;i++)
{
minn=maxn;
for (int j=1;j<=n;j++)
if (b[j]==0&&c[j]<minn) //求距离集合最近的点
{
minn=c[j];
o=j;
}
if(o==0) break;
b[o]=1; //进入集合
for (int j=1;j<=n;j++)
if (b[j]==0&&c[j]>c[o]+a[o][j])
c[j]=c[o]+a[o][j]; //重新计算最短路
}
a[x[k]][y[k]]=l;
if (l+c[y[k]]<ans) ans=l+c[y[k]]; //判断答案
}
if(ans<maxn) printf("%d",ans);
else puts("No solution");
return 0;
}