Smile House 經過最少的點的正環
阿新 • • 發佈:2020-12-07
題目
(Smile House)https://ac.nowcoder.com/acm/problem/109328
題目大意
有n個點,2*m條邊。輸出圖中經過點數最少的正環的點,不存在正環輸出0。
保證輸入沒有重邊和自環。(1<=n<=300, 0<=m<=n(n-1)/2)
輸入
第一行n,m。
接下來的m行。每行a, b, c, d;
a到b的邊權為c, b到a的邊權為d。
輸出
最小的正環的點。不存在就輸出0。
思路
最小環
對於最小環,它一定經過圖中的一條邊。
那麼我們列舉每一條邊。u-v,我們去掉u-v跑v-u的最短路+W(u-v)就是包含這條邊的最小環。
我們也可以用Floyd。
用\(dist[i][j]:i到j邊的長度。沒有邊就INF。\)
用\(Path[i][j]:i到j的最短路\)
那麼\(min(Path[i][j]+dist[j][i])\)就是一個環。
#include<iostream> #include<algorithm> #include<cstdio> using namespace std; #define INF 10000000 int N,M; int Path[105][105]; int dist[105][105]; void Floyd3() { int ans=INF; for(int k=1; k<=N; k++) { for(int i=1; i<k; i++) { for(int j=i+1; j<k; j++) {//保證3個不相同的點 ans=min(ans,Path[i][k]+Path[k][j]+dist[i][j]); // 得到從 i點出發再回到 i點的最小環 } } for(int i=1; i<=N; i++) { for(int j=1; j<=N; j++) { dist[i][j]=min(dist[i][j],dist[i][k]+dist[k][j]); // 得到 i,j兩點的最短路徑 } } } if(ans<INF) printf("%d\n",ans); else puts("It's impossible."); } int main() { int a,b,c,res; while(scanf("%d %d",&N,&M)!=EOF){ for(int i=1;i<=N;i++){ for(int j=1;j<=N;j++){ Path[i][j]=dist[i][j]=(i==j?0:INF); } } for(int i=0;i<M;i++){ scanf("%d %d %d",&a,&b,&c); Path[a][b]=Path[b][a]=dist[a][b]=dist[b][a]=min(Path[a][b],c); } Floyd3(); } return 0; }
最小正環
就是這題了。
#include <bits/stdc++.h> using namespace std; int dp[11][305][305]; int tmp[305][305], f[305][305], lg[305]; int main(){ memset(dp, -0x3f, sizeof(dp)); memset(f, -0x3f, sizeof(f)); int n, m; scanf("%d%d", &n, &m); for(int i=1;i<=n;i++){ lg[i]=lg[i-1]+(1<<lg[i-1]==i); } for(int i=1; i<=m; i++){ int a, b; scanf("%d%d", &a, &b); scanf("%d%d", &dp[0][a][b], &dp[0][b][a]); } for(int i=1; i<=n; i++) dp[0][i][i]=f[i][i]=0; for(int s=1; s<=lg[n]; s++){ for(int k=1; k<=n; k++){ for(int i=1; i<=n; i++){ for(int j=1; j<=n; j++){ dp[s][i][j]=max(dp[s][i][j], dp[s-1][i][k]+dp[s-1][k][j]); } } } } int ans=0; for(int s=lg[n]; s>=0; s--){ memset(tmp, -0x3f, sizeof(tmp)); for(int k=1; k<=n; k++){ for(int i=1; i<=n; i++){ for(int j=1; j<=n; j++){ tmp[i][j]=max(tmp[i][j], f[i][k]+dp[s][k][j]); } } } int flag=0; for(int i=1; i<=n; i++){ if(tmp[i][i]>0){//存在正環 flag=1; break; } } if(flag) continue; else ans+=(1<<s), memcpy(f, tmp, sizeof(tmp));//沒有正環 f是統計已經最多走了ans邊了的最短路 } if(ans>=n) printf("0\n");//沒有正環 else printf("%d\n", ans+1); return 0; }