POJ 3311 Hie with the Pie (Floyd+状态压缩)

举报
Linux猿 发表于 2021/08/05 00:39:16 2021/08/05
【摘要】 题目链接~~> 做题感悟:本来做背包题的,其中牵扯到TSP问题结果就晕了,于是就学TSP但是这题貌似不是正宗的TSP问题。 解题思路:Floyd + 状态压缩                  第一步:先用Floyd 处理一下图得到任意两点之间的最短路。   &n...

题目链接~~>

做题感悟:本来做背包题的,其中牵扯到TSP问题结果就晕了,于是就学TSP但是这题貌似不是正宗的TSP问题。

解题思路:Floyd + 状态压缩

                 第一步:先用Floyd 处理一下图得到任意两点之间的最短路。

                 第二步:状态压缩枚举所有情况,dp [ i ] [ j ] 代表在状态 i 下(i 表示成二进制,某位为 0 代表未经过此点,如果为 1 代表经过此点)从 0 点出发到经过状态 i 中的所有点后到达 j 的最短路径。

                       动态方程:dp [ i ] [ j ]  = min { dp [ i ^(1<< i ) ] [ j ] + d[ j ] [ i ] ,dp [ i ] [ j ] },其中 j 存在于状态 i 中,其实和Floyd 的原理差不多,表示以 j 为中间点后是否使路径更短。

代码:


  
  1. #include<stdio.h>
  2. #include<iomanip>
  3. #include<vector>
  4. #include<queue>
  5. #include<fstream>
  6. #include<string.h>
  7. #include<stdlib.h>
  8. #include<string.h>
  9. #include<algorithm>
  10. #include<iostream>
  11. #define INT long long int
  12. using namespace std ;
  13. const int INF = 99999999 ;
  14. const int MX = 10 + 10 ;
  15. int n ;
  16. int dp[1<<11][MX],d[MX][MX] ;
  17. void Floyd() // 求任意两点之间的最短路径
  18. {
  19. for(int k=0 ;k<=n ;k++)
  20. for(int i=0 ;i<=n ;i++)
  21. for(int j=0 ;j<=n ;j++)
  22. d[i][j]=min(d[i][k]+d[k][j],d[i][j]) ;
  23. }
  24. void DP_SC()
  25. {
  26. for(int S=0 ;S<(1<<n) ;S++) // 枚举所有状态
  27. for(int i=1 ;i<=n ;i++)
  28. if(S&(1<<(i-1)))
  29. {
  30. if(S==1<<(i-1)) dp[S][i]=d[0][i] ; // 如果就一个点 i
  31. else
  32. {
  33. dp[S][i]=INF ;
  34. for(int j=1 ;j<=n ;j++)// 枚举中间点
  35. {
  36. if(S&(1<<(j-1))&&i!=j)
  37. dp[S][i]=min(dp[S][i],dp[S^(1<<(i-1))][j]+d[j][i]) ;
  38. }
  39. }
  40. }
  41. int S = (1<<n)-1 ;
  42. int ans = dp[S][1]+d[1][0] ;
  43. for(int i=1 ;i<=n ;i++)
  44. ans = min(dp[S][i]+d[i][0],ans) ;
  45. cout<<ans<<endl ;
  46. }
  47. int main()
  48. {
  49. while(scanf("%d",&n),n)
  50. {
  51. for(int i=0 ;i<=n ;i++)
  52. for(int j=0 ;j<=n ;j++)
  53. scanf("%d",&d[i][j]) ;
  54. Floyd() ;
  55. DP_SC() ;
  56. }
  57. return 0 ;
  58. }

代码:


  
  1. #include<stdio.h>
  2. #include<iomanip>
  3. #include<vector>
  4. #include<queue>
  5. #include<fstream>
  6. #include<string.h>
  7. #include<stdlib.h>
  8. #include<string.h>
  9. #include<algorithm>
  10. #include<iostream>
  11. #define INT long long int
  12. using namespace std ;
  13. const int INF = 999999999 ;
  14. const int MX = 10 + 10 ;
  15. const int MY = 11 ;
  16. int n ;
  17. int dp[1<<MY][MX],d[MX][MX] ;
  18. void Floyd() // 求最短路
  19. {
  20. for(int k=0 ;k<n ;k++)
  21. for(int i=0 ;i<n ;i++)
  22. for(int j=0 ;j<n ;j++)
  23. d[i][j]=min(d[i][j],d[i][k]+d[k][j]) ;
  24. }
  25. void DP_SC()
  26. {
  27. memset(dp,-1,sizeof(dp)) ;
  28. for(int i=0 ;i<n ;i++)
  29. dp[1<<i][i]=d[0][i] ;
  30. for(int S=0 ;S<(1<<n) ;S++) // 枚举每一种状态
  31. for(int i=0 ;i<n ;i++)
  32. if(dp[S][i]!=-1) // 以 i 点为中间点更新 j 点
  33. {
  34. for(int j=0 ;j<n ;j++)
  35. if(i!=j&&!(S&(1<<j)))
  36. {
  37. if(dp[S|(1<<j)][j]==-1)
  38. dp[S|(1<<j)][j]=dp[S][i]+d[i][j] ;
  39. else dp[S|(1<<j)][j]=min(dp[S][i]+d[i][j],dp[S|(1<<j)][j]) ;
  40. }
  41. }
  42. int ans = INF ; // 寻找最优解
  43. for(int i=0 ;i<n ;i++)
  44. if(dp[(1<<n)-1][i]!=-1)
  45. ans = min(ans,dp[(1<<n)-1][i]+d[i][0]) ;
  46. cout<<ans<<endl ;
  47. }
  48. int main()
  49. {
  50. while(scanf("%d",&n),n)
  51. {
  52. n++ ;
  53. for(int i=0 ;i<n ;i++)
  54. for(int j=0 ;j<n ;j++)
  55. scanf("%d",&d[i][j]) ;
  56. Floyd() ;
  57. DP_SC() ;
  58. }
  59. return 0 ;
  60. }





   




文章来源: blog.csdn.net,作者:Linux猿,版权归原作者所有,如需转载,请联系作者。

原文链接:blog.csdn.net/nyist_zxp/article/details/37935303

【版权声明】本文为华为云社区用户转载文章,如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。