做题感悟:
这题可谓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 ;
}