宝塔服务器面板,一键全能部署及管理,送你10850元礼包,点我领取
3122 奶牛代理商 VIII
时间限制: 3 s
空间限制: 256000 KB
题目等级 : 大师 Master
题目描述 Description
小徐是USACO中国区的奶牛代理商,专门出售质优价廉的“FJ”牌奶牛。
有一天,她的奶牛卖完了,她得去美国进货。
她需要去N个奶牛农场询问价格(小徐是个认真的人,买东西一定要货比三家)。
给你一个邻接矩阵,表示N个农场间的路径长度,求小徐最少走多少路。从农场1出发,最后回到出发点买)
输入描述 Input Description
N
邻接矩阵
输出描述 Output Description
答案(见描述)
样例输入 Sample Input
3
0 1 2
3 0 10
2 0 0
样例输出 Sample Output
5
数据范围及提示 Data Size & Hint
N<=15,路径长度<=1000
TSP
分类标签 Tags 点此展开
状压DP好恶心啊。。
这道题的关键点有两个,
1.走过所有的点
2.最短路径
第2个最短路径比较好解决,n<=16的话,,一遍Floyd就可以
但是第一个条件,要走过所有的点。
我们可以考虑用状态压缩的方法来实现
我们可以用一个二进制的字符串表示这个点是否走过,比如说110表示已经走过了1和2这两个点,第3个点还没有经过
代码思路:
设置一个dp数组,dp[now][j]表示在now状态下,到达点j所需要的花费
首先我们需要暴力枚举i和j两点,来求最短距离
其次,我们还需要枚举一个能够包揽所有状态的变量now,来记录每一个能够到达的状态
当状态now可以到达j的话,那么说明我们可以通过这个状态到达i(i和j之间必定有路径)
最后枚举每个点,取一下最小值就可以
细节问题:
1.跑floyd的时候不要预先设定最大值,因为每两个点(不相同)之间必定有边相连
2.dp数组的第一位必须要开的足够大,最小是2^16,因为第一维记录的是状态而不是大小
3.now<=1<<n)-1:
当n==3时,1<<3 == 2^3 == 8 == 1000
1000-1=111正好是三个点都到达的理想情况
4.now&1<<j-1))
j-1是为了不超边界且枚举出所有情况
首先要明确,1<<j-1)得到的一定是一个2^x的数,转换成二进制一定是1+000…..的形式
那么当now&1<<j-1))有值时,就说状态now是可以到达j点的
5.now|1<<i-1))
在进行这个运算的时候,now一定是满足now&1<<j-1))!=0的(程序满足顺序执行)
那么通过now状态一定可以到达j点
而且1<<i-1)也一定是一个2^x的数
所以now|1<<i-1))就是一个可以通过j到达i产生的新状态
举个栗子:
now=110010
i=100
那么结果就是110110
代码:
1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include<cmath> 5 using namespace std; 6 const int MAXN=30; 7 int readint & n) 8 { 9 char p='+';int x=0; 10 whilep<'0'||p>'9') 11 p=getchar); 12 whilep>='0'&&p<='9') 13 x=x*10+p-48,p=getchar); 14 n=x; 15 } 16 int dp[MAXN*2000][MAXN]; 17 int dis[MAXN][MAXN]; 18 int n; 19 void floyed) 20 { 21 forint i=1;i<=n;i++) 22 forint j=1;j<=n;j++) 23 forint k=1;k<=n;k++) 24 ifi!=j&&j!=k&&i!=k) 25 dis[i][j]=mindis[i][j],dis[i][k]+dis[k][j]); 26 } 27 void zhuangya) 28 { 29 /*forint i=1;i<=n;i++) 30 { 31 forint j=1;j<=n;j++) 32 { 33 cout<<dis[i][j]<<" "; 34 } 35 cout<<endl; 36 }*/ 37 memsetdp,0xf,sizeofdp)); 38 dp[1][1]=0; 39 forint now=0;now<=1<<n)-1;now++) 40 forint i=1;i<=n;i++) 41 forint j=1;j<=n;j++) 42 ifnow&1<<j-1)))&&i!=j) 43 { 44 dp[now|1<<i-1))][i]= 45 min 46 47 dp[now|1<<i-1))][i], 48 dp[now][j]+dis[j][i] 49 ); 50 } 51 int ans=0x7ffffff; 52 forint i=2;i<=n;i++) 53 { 54 ans=minans,dp[1<<n)-1][i]+dis[i][1]); 55 } 56 cout<<ans; 57 } 58 int main) 59 { 60 readn); 61 forint i=1;i<=n;i++) 62 forint j=1;j<=n;j++) 63 readdis[i][j]); 64 floyed); 65 zhuangya); 66 return 0; 67 }