藍書(演算法競賽進階指南)刷題記錄——POJ1734 Sightseeing trip(無向圖最小環)
阿新 • • 發佈:2018-11-10
題目: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; }