题目:http://poj.org/problem?id=1734
方法有点像floyd。若与k直接相连的 i 和 j 在不经过k的情况下已经连通,则有环。
注意区分直接连接和间接连接。
* 路径记录很好,pre[i][j]表示 i 到 j 的路径上 j 的前一个点;用固定的 i 保证了不混乱。新加入k的时候注意维护。
#include<iostream> #include<cstdio> #include<cstring> using namespace std; typedef long long ll; const ll N=105,INF=0x7fffffff; int n,m,pre[N][N],ans[N],cnt; ll f[N][N],mn=INF,b[N][N]; int main() { int x,y;ll z; memset(f,1,sizeof f); scanf("%d%d",&n,&m); for(int i=1;i<=m;i++) { scanf("%d%d%lld",&x,&y,&z); if(b[x][y]) f[x][y]=f[y][x]=b[x][y]=b[y][x]=min(f[x][y],z); else { f[x][y]=f[y][x]=z; b[x][y]=b[y][x]=z; pre[x][y]=x;pre[y][x]=y; } } for(int k=1;k<=n;k++) for(int i=1;i<=n;i++) for(int j=i+1;j<=n;j++) { if(b[i][k]&&b[j][k]&&f[i][j]<INF) { ll tmp=f[i][j]+b[i][k]+b[j][k];//不是f[i][k] // if(k==5&&i==2&&j==3)printf("tmp=%lld ",tmp); if(tmp<mn) { // printf("i=%d j=%d k=%d fij=%lld tmp=%lld ",i,j,k,f[i][j],tmp); // printf("ij=%lld ik=%lld jk=%lld ",f[i][j],f[i][k],f[j][k]); mn=tmp; cnt=0; for(int u=j;u!=i;u=pre[i][u])ans[++cnt]=u; ans[++cnt]=i;ans[++cnt]=k; } } // if(f[i][k]>INF||f[k][j]>INF)continue;// ll tmp=f[i][k]+f[k][j]; if(tmp<f[i][j]) { f[i][j]=f[j][i]=tmp; pre[i][j]=pre[k][j]; pre[j][i]=pre[k][i]; // pre[i][j]=pre[j][i]=k;//错!不是直接相连! // pre[i][k]=i;pre[j][k]=j; // pre[k][i]=k;pre[k][j]=k;// } } if(cnt)for(int i=1;i<=cnt;i++)printf("%d ",ans[i]); else printf("No solution."); return 0; }