Acmer先生决定访问n座城市。他可以空降到任意城市,然后开始访问,要求访问到所有城市,任何一个城市访问的次数不少于1次,不多于2次。n座城市间有m条道路,每条道路都有路费,求Acmer先生完成旅行所需要花费的最小费用。
第一行是n,m,后面有m行,有3个整数a,b,c,表示城市a和b之间的路费是c
输出最少花费,如果不能完成旅行,则输出-1;
这里考察的是三进制状态压缩dp
#include<iostream> #include<cstring> #include<algorithm> using namespace std; const int inf=0x3f3f3f3f; int n,m; int bit[12]={0,1,3,9,27,81,243,729,2187,6561,19683,59049};//三进制每一位的权值 int tri[60000][11]; int dp[11][60000]; int graph[11][11];//存图 void make_trb(){ //初始化,求所有可能的路径 for(int i=0;i<59050;++i) //共3的10次方=59050因为题目要求1=<n<=10 { int t=i; for(int j=1;j<=10;++j){ tri[i][j]=t%3;t/=3; } } } int comp_dp(){ int ans=inf; memset(dp,inf,sizeof(dp)); for(int i=0;i<=n;i++) dp[i][bit[i]]=0; //bit[i]是第i个城市,起点是任意的 for(int i=0;i<bit[n+1];i++){ int flag=1; //所有的城市都遍历过一次以上 for(int j=1;j<=n;j++) //选一个终点 { if(tri[i][j]==0) //判断终点位是不是0 { flag=0; //还没有经过所有点 continue; } if(i==j) continue; for(int k=1;k<=n;k++) { int l=i-bit[j]; //i状态的第j位置0 if( tri[i][k]==0) continue; dp[j][i]=min(dp[j][i],dp[k][l]+graph[k][j]); } } if(flag) //找最少费用 for(int j=1;j<=n;j++) ans=min(ans,dp[j][i]); } return ans; } int main() { std::ios::sync_with_stdio(false),cin.tie(0),cout.tie(0);//打消iostream的输入和输出缓存,节省时间 make_trb(); while(cin>>n>>m){ memset(graph,inf,sizeof(graph)); while(m--){ int a,b,c; cin>>a>>b>>c; if(c<graph[a][b]) graph[a][b]=graph[b][a]=c; } int ans=comp_dp(); if(ans==inf) cout<<"-1"<<endl; else cout<<ans<<endl; } }