现在的位置: 首页 > 综合 > 正文

UVA 10604 – Chemical Reaction (状态压缩)

2019年02月23日 ⁄ 综合 ⁄ 共 2226字 ⁄ 字号 评论关闭

题目链接~~>

做题感悟:

                   这题可谓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 ;
}

抱歉!评论已关闭.