蓝书(算法竞赛进阶指南)刷题记录——POJ1734 Sightseeing trip(无向图最小环)

版权声明:转载请注明原出处啦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的环的权值大小可以表示为dis[i][j]+v[j][k]+v[k][i].

那么我们可以把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;
}

猜你喜欢

转载自blog.csdn.net/hzk_cpp/article/details/83003463