1. 程式人生 > >藍書(演算法競賽進階指南)刷題記錄——POJ1734 Sightseeing trip(無向圖最小環)

藍書(演算法競賽進階指南)刷題記錄——POJ1734 Sightseeing trip(無向圖最小環)

題目: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;
}