题目链接~~>
做题感悟:
这题可谓AC的很艰难,开始一读题,再定睛一看数据,呵呵,明显状态压缩也 !这里扯个闲篇叙述一下自己的AC历程,(如果您感觉没必要请直接看解体思路,本人感觉很有必要写一下):首先开始用状态压缩写,但是写的有点乱,调试了很久终于把样例过了,然后就高高兴兴的提交了,很快就 wa,然后就开始找错误,找到了一些错误,怕有大数据又把 int --> long long int ,接着又提交无情的返回了 wa ,感觉没什么错误了啊!以为有什么格式错误或者题意不明白,又读了一遍题意,题意没理解错(‘ / ’ ‘ . ' 感觉就是忽悠人的),到了下午把自己的代码拿出来重新再看了一遍,以前曾经因某个字符错了坑了很久,这次细心的看了一番没发现什么错误,看这题看的都看烦了,果断百度了一下,很不幸的是只有 5 个人写了博客,而且都是用的一种方法开六维数组记忆化搜索,感情是模仿的一个人的 ,跟自己的思路完全不一样,本来想学习一下,但是坚定的认为自己的代码是对的,又开始想自己的代码有什么错误,想了一会没想明白,就放了一下等明天再看。第二天一来,就有种很想解决这题的冲动,明明自己的思路是对的,最后无奈之下,生成了数据,然后开始找自己的错误,发现这样找比较好找,开始找到了一个错误,改后怀着忐忑的心情提交了一下又 wa了 ,然后又重新生成了几组数据,自己手算了一下发现有错误的然后把错误改正后,提交,成功AC。
以后注意的地方:(1),写完程序后应该找几组数据测试一下,不要茫然提交。 (2), 注意题目的数据范围,自己标记的值不要在数据范围内。
解体思路: 状态压缩
数据范围很小,用状态压缩完全可以,用状态 S 标记融合了哪些试管,每一位表示一个试管,(1<<k) -1 代表把所有的试管都融合的剩下一种试剂所达到的状态,那么就可以用 dp [ S ] [ i ] 代表融合试管达到状态 S 后融合成试剂 i 所得到的最少热量,动态方程:dp [ S | S1 ] [ k ] = min ( dp [ S|S1 ] [ k ] , dp [ S ][ i ] + dp [ S1 ] [ j ] + wij ) ;(wij 代表 i 与 j 融合所产生的热量 ,注意wij 与 wji 不一样这里只说一种的状态方程 ,且S 与 S1 相与为 0),具体细节请看代码。
代码:
#include<iostream> #include<fstream> #include<iomanip> #include<ctime> #include<fstream> #include<sstream> #include<stack> #include<cstring> #include<cmath> #include<map> #include<vector> #include<cstdio> #include<algorithm> using namespace std ; const int mod = 1e9 + 7 ; const int INF = 999999999 ; const int MY = 10 + 10 ; const int MX = (1<<11) + 10 ; int k ,n ; int dp[MX][MY] ,g[MY] ; struct node { int num ,w ; }T[MY][MY] ; void DP_SC() { int num ,w ,best = INF ; for(int S = 0 ;S < (1<<k) ;S++) for(int i = 1 ;i <= n ;i++) if(dp[S][i] != INF) { for(int S1 = 0 ;S1 < (1<<k) ;S1++) // (1)开始手残了把这写成 (1<<k) - 1 { if((S&S1)) continue ; for(int j = 1 ;j <= n ;j++) if(dp[S1][j] != INF) { num = T[i][j].num ; w = T[i][j].w ;// (2)开始 dp[S|S1][num] 用了引用,用错了 dp[S|S1][num] = min(dp[S|S1][num],dp[S][i] + dp[S1][j] + w) ; num = T[j][i].num ; w = T[j][i].w ; dp[S|S1][num] = min(dp[S|S1][num] ,dp[S][i] + dp[S1][j] + w) ; } } } for(int i = 1 ;i <= n ;i++) best = min(best ,dp[(1<<k)-1][i]) ; cout<<best<<endl ; } void input() // 输入 { char s[10] ; scanf("%d" ,&n) ; memset(T ,0 ,sizeof(T)) ; memset(g ,0 ,sizeof(g)) ; for(int i = 1 ;i <= n ;i++) for(int j = 1 ;j <= n ;j++) scanf("%d%d" ,&T[i][j].num ,&T[i][j].w) ; scanf("%d" ,&k) ; for(int S = 0 ;S < (1<<k) ;S++) // 注意不要初始化为 -1 ,注意题目数据范围 for(int i = 1 ;i <= n ;i++) dp[S][i] = INF ; for(int i = 0 ;i < k ;i++) { scanf("%d" ,&g[i]) ; dp[1<<i][g[i]] = 0 ; // 初始化一个试管的时候 } scanf("%s" ,s) ; } int main() { //freopen("in.txt" ,"r" ,stdin) ; //freopen("out.txt" ,"w" ,stdout) ; int Tx ; scanf("%d" ,&Tx) ; while(Tx--) { input() ; DP_SC() ; } return 0 ; }