ZOJ3471 Most Powerful,状态压缩DP

来源:互联网 发布:标准差例题算法 编辑:程序博客网 时间:2024/05/07 18:34

这题一开始没有什么想法,后来只能上网看别人的解题报告,看到了状态压缩DP这种做法,好神奇。。。

对于有n个原子,在任何一个状态下,每个原子只有两种状态,要么就是已经被消灭,要么就是还余下来。我们用0表示某个原子还存在,用1表示某个原子被消灭了,这样我们就可以用0到2^n-1个数字来表示任何一种状态了。

对于每一个状态i,我们可以从中挑选两个还存在的原子j和k来进行碰撞,看看碰撞后的能量有没有比原来的多。。。这个很纠结的说明白,我们看看状态转移方程吧

dp[i | (1<<k)] = max(dp[i|(1<<k)],dp[i]+map[j][k]);
i表示第种状态,k表示碰撞后消失的原子,j表示碰撞后还存在的原子。等式左边的dp[i|1<<k]表示碰撞过后的状态的能量,等式右边的dp[i|1<<k]表示原来的能量,因为经过碰撞,k会消失,所以要用i|1<<k来表示。右边的dp[i]+map[j][k]表示在状态i中,经过j和k碰撞,余下j,变成i|1<<k状态后的新的能量。

i经过0到2^n-1次循环,每次循环都循环挑出任意两个还存在的原子碰撞后,最后的能量都储存到dp数组中。最后对dp检索出最大值,就是结果了。


/******************************************************************************* # Author : Neo Fung # Email : neosfung@gmail.com # Last modified: 2011-10-17 08:54 # Filename: ZOJ3471 Most Powerful.cpp # Description :  ******************************************************************************/// #include "stdafx.h"// #define DEBUG#include <fstream>#include <stdio.h>#include <iostream>#include <string.h>#include <string>#include <memory.h>#include <limits.h>using namespace std;int map[15][15];int dp[1<<11];int main(void){#ifdef DEBUG  freopen("data.txt","r",stdin);  #endif  int n;while(scanf("%d",&n)&&n){int maxint=1<<n;for(int i=0;i<n;++i)for(int j=0;j<n;++j)scanf("%d",&map[i][j]);memset(dp,0,sizeof(dp));for(int i=0;i<maxint;++i)//状态从0到2^n-1种for(int j=0;j<n;++j){if(i & (1<<j)) continue;//如果在状态i中第j个原子已消失,不计算for(int k=0;k<n;++k){if(i & (1<<k)) continue;//如果在状态i中第k个原子已消失,不计算if(j==k) continue;//如果碰撞的两个原子相同,不计算dp[i | (1<<k)] = max(dp[i|(1<<k)],dp[i]+map[j][k]);//状态转移方程}}int ans=0;for(int i=0;i<maxint;++i)if(dp[i]>ans)ans=dp[i];printf("%d\n",ans);}return 0;}



原创粉丝点击