版权声明:转载请注明原出处啦QAQ(虽然应该也没人转载): https://blog.csdn.net/hzk_cpp/article/details/83003463
题目:poj1734.
题目大意:给定一张无向图,求这张无向图边权和最小的节点大于3个的环,若有解输出任意一个方案,否则输出“No solution.”.
这就是一个较为简单的floyd应用.
我们可以先把floyd模板写下来看看floyd有什么特殊的性质:
void floyd(){
for (int k=1;k<=n;k++)
for (int i=1;i<=n;i++)
for (int j=1;j<=n;j++)
dis[i][j]=min(dis[i][j],dis[i][k]+dis[k][j]);
}
好吧这样可能看不出来,我们可以发现由于当前i到j的最短路上经过的点的编号都是小于k的,所以我们现在就可以加两条边(i,k)和(k,j),那么一个经过点k的节点数大于3的环的权值大小可以表示为.
那么我们可以把floyd计算最短路的同时,也顺便计算一下最小环的大小.
但是我们发现每一个k枚举到的环的节点编号大小都不超过k,那么正确性如何保证?
因为这是一张无向图,无向图具有对称性,所以这样做并没有什么问题.
代码如下:
//#include<bits/stdc++.h>
#include<iostream>
#include<vector>
using namespace std;
#define Abigail inline void
typedef long long LL;
const int N=100,INF=(1<<29)-1; //写成(1<<30)-1就凉了
int n,m;
int v[N+9][N+9],dis[N+9][N+9],ans,pre[N+9][N+9];
vector<int>path;
void get_path(int start,int finish){
if (!pre[start][finish]) return;
get_path(start,pre[start][finish]);
path.push_back(pre[start][finish]);
get_path(pre[start][finish],finish);
}
void floyd(){
ans=INF;
for (int k=1;k<=n;k++){
for (int i=1;i<k;i++)
for (int j=i+1;j<k;j++) //因为要求方案有序
if (dis[i][j]+v[j][k]+v[k][i]<ans){
ans=dis[i][j]+v[j][k]+v[k][i];
path.clear();
path.push_back(i);
get_path(i,j);
path.push_back(j);
path.push_back(k);
}
for (int i=1;i<=n;i++)
for (int j=1;j<=n;j++)
if (dis[i][j]>dis[i][k]+dis[k][j]){
dis[i][j]=dis[i][k]+dis[k][j];
pre[i][j]=k;
}
}
}
Abigail into(){
scanf("%d%d",&n,&m);
for (int i=1;i<=n;i++)
for (int j=1;j<=n;j++)
if (i^j) v[i][j]=INF;
int x,y,z;
for (int i=1;i<=m;i++){
scanf("%d%d%d",&x,&y,&z);
if (v[x][y]<=z) continue;
v[x][y]=v[y][x]=z;
}
}
Abigail work(){
for (int i=1;i<=n;i++)
for (int j=1;j<=n;j++)
dis[i][j]=v[i][j];
floyd();
}
Abigail outo(){
if (ans>=INF) printf("No solution.\n");
else {
for (vector<int>::iterator it=path.begin();it!=path.end();it++)
printf("%d ",*it);
printf("\n");
}
}
int main(){
into();
work();
outo();
return 0;
}