用dp来求最短路,虽然效率低,但是状态的概念方便解决最短路问题中的很多限制,也便于压缩以保存更多信息。
本题要求访问全图,且每个节点不能访问两次以上。所以用一个三进制数保存全图的访问状态(3^10,空间是足够的),用dp[z+bit[j]][j]=dp[z][i]+ct[i][j]就可以表示,从上一状态以i为结束点,转移到把j加入路径末端后的状态(感叹一下位运算的神奇)。
// // main.cpp // hdu_3001 // // Created by Luke on 2016/11/12. // Copyright ? 2016年 Luke. All rights reserved. // #include <iostream> #include <cmath> #include <algorithm> #include <cstdio> #define N 15 #define zip 70000 #define INF 919900000//原来要开这么大哇 using namespace std; int n,m; int ct[N][N];//存边权 int dp[zip][N];//z状态下,以j为终点的路径费用 int bit[20]; void addE(int from,int to,int fee); void ini(); int digit(int num,int pos);//返回压缩后的当前位置状态 int solve() { int ans=INF; for(int z=0;z<bit[n];z++) { int f=1; for(int j=0;j<n;j++)//表示以j结尾,从位置i转移过来 { int fix=digit(z,j); if(fix==2) continue; if(fix==0) f=0; //if(dp[z][j]==INF) continue; for(int i=0;i<n&&z+bit[j]<bit[n];i++) dp[z+bit[j]][j]=min(dp[z+bit[j]][j],dp[z][i]+ct[i][j]); } if(f)//如果是合法状态,就更新一遍ans for(int i=0;i<n;i++) ans=min(ans,dp[z][i]); } if(ans==INF) return -1; return ans; } int main(int argc, const char * argv[]) { cin.sync_with_stdio(false); bit[0]=1; for(int i=1;i<=15;i++) bit[i]=bit[i-1]*3; while(cin>>n>>m) { int a,b,c; ini(); for(int i=0;i<m;i++) cin>>a>>b>>c,addE(a,b,c); cout<<solve()<<endl; } return 0; } void addE(int from,int to,int fee) { from--,to--;//为了节约空间,节点从0开始计数 ct[from][to]=ct[to][from]=min(ct[to][from],fee); } void ini() { for(int i=0;i<N;i++) for(int j=0;j<N;j++) ct[i][j]=INF; for(int i=0;i<zip;i++) for(int j=0;j<N;j++) { if(bit[j]==i) dp[i][j]=0; else dp[i][j]=INF; } } int digit(int num,int pos) { for(int i=0;i<pos;i++) num/=3; return num%3; }
时间: 2024-11-05 02:32:30