HDU_3828 A + B problem 状态dp
2012-07-26 15:14
211 查看
http://acm.hdu.edu.cn/showproblem.php?pid=3828
题意:
给你N个数,求N个数在满足下面3个条件的情况下相加的最小和。
条件一: 相加的两个数是二进制相加;
条件二:相加的两个数A,B , A的后缀可以和B的前缀合并成一个
条件三:相加的两个数A,B,如果A是B的子串,则A可以不算。
思路:
很好的一道状态压缩dp。对于两个数,我们可以发现,如果这两个数都不是各自的子串,那个
这两个数相加,要是A前B后,或者B前A后,只有这两种情况。这样分析了之后我们似乎就可以
推导出本题是否可以用贪心的求法,也就是说每次都是求一个值最小的那个。但是这个贪心思路
是不正确的,那么我们就可以考虑dp,但是线性的dp是不满足最优子性质的, 那么我们就可以用
状态压缩来记录当前的状态。因此本题的做法是这样的:用dp[i][j]表示状态为j,以i为前缀的最小
长度,求出最小长度之后通过构造最小串就可以得出问题的解了。
题意:
给你N个数,求N个数在满足下面3个条件的情况下相加的最小和。
条件一: 相加的两个数是二进制相加;
条件二:相加的两个数A,B , A的后缀可以和B的前缀合并成一个
条件三:相加的两个数A,B,如果A是B的子串,则A可以不算。
思路:
很好的一道状态压缩dp。对于两个数,我们可以发现,如果这两个数都不是各自的子串,那个
这两个数相加,要是A前B后,或者B前A后,只有这两种情况。这样分析了之后我们似乎就可以
推导出本题是否可以用贪心的求法,也就是说每次都是求一个值最小的那个。但是这个贪心思路
是不正确的,那么我们就可以考虑dp,但是线性的dp是不满足最优子性质的, 那么我们就可以用
状态压缩来记录当前的状态。因此本题的做法是这样的:用dp[i][j]表示状态为j,以i为前缀的最小
长度,求出最小长度之后通过构造最小串就可以得出问题的解了。
#include<string> #include<iostream> #include<algorithm> #include<string.h> #include <cstdio> #define MIN(a,b) ( (a)>(b)?(b):(a) ) using namespace std; typedef __int64 LL ; const LL Mod = 1000000009 ; int n , N; const int MM = 16 ; string word[MM] ; int ll[MM][MM] ; int dp[MM][1<<16] ; string ans ; void init(){ LL a ; for(int i=0;i<n;i++){ cin >> a ; word[i] = "" ; while( a ){ if( a&1 ) word[i] += '1' ; else word[i] += '0' ; a >>= 1 ; } reverse( word[i].begin() , word[i].end() ); } } void move(){ for(int i=0;i<n;i++){ for(int j=0;j<n;j++){ if( i!=j && word[j].find( word[i] ) != string::npos ){ word[i--] = word[ -- n ] ; break ; } } } } void deal1(){ for(int i=0;i<n;i++){ for(int j=0;j<n;j++){ int&lap = ll[i][j] = word[i].size() ; while( word[i].substr(word[i].size() - lap) != word[j].substr(0 , lap) ) lap -- ; } } } int DP(int i , int j){ if( dp[i][j] != -1 ) return dp[i][j] ; int jj = j ^ ( 1<<i ) ; dp[i][j] = jj ? (1<<30) : word[i].size() ; for(int ii=0;ii<n;ii++){ if( (jj&(1<<ii)) != 0 ){ dp[i][j] = MIN( dp[i][j] , DP(ii,jj) + word[i].size() - ll[i][ii] ); } } return dp[i][j] ; } void deal2(){ N = 1<<n ; memset(dp , -1, sizeof(dp)); for(int i=0;i<n;i++){ DP( i , N-1 ); } //DP(); int m = N - 1 ; ans = "" ; int prev = -1 ; while( m ){ int best = -1; int bestLen; string bestAdd; for (int f = 0; f < n; f++) if (m & (1 << f) ){ int len = dp[f][m]; string add = word[f]; if (prev >= 0) { len -= ll[prev][f]; add = add.substr(ll[prev][f]); } if (best < 0 || len < bestLen || len == bestLen && add < bestAdd) { best = f; bestLen = len; bestAdd = add; } } ans += bestAdd; prev = best; m ^= ( 1 << best ) ; } int cnt = ans.size() ; LL res = 0 ,add = 1 ; for(int i=cnt-1;i>=0;i--){ if( ans[i] == '1' ) res = ( res + add ) % Mod ; add = add * 2 % Mod ; } cout << res << endl ; } int main(){ while( cin >> n ){ init() ; move() ; deal1() ; deal2() ; } return 0 ; }
相关文章推荐
- Hdu 4057 Rescue the Rabbit (AC自动机+状态压缩dp) - 2011 ACM-ICPC Dalian Regional Contest Problem G
- Hdu 4089 Activation (概率dp) - 2011 ACM-ICPC Beijing Regional Contest Problem I
- HDU 4539 郑厂长系列故事——排兵布阵 (状态压缩DP)
- HDU 4295 状态压缩dp + KMP
- !HDU 1574 RP-dp-(重点在状态确定)
- HDU-1300(基础方程DP-遍历之前所有状态)
- DP Problem D:Humble Numbers(HDU 1058)
- hdu 5464 Clarke and problem(dp)
- HDU 3828 A+B problem
- HDU 1074 课程安排 (状态压缩+DP,经典)
- HDU 1693(状态压缩 插头DP)
- HDU 1565 方格取数(1)(状态压缩DP)
- DP Problem I:超级楼梯(HDU 2040)
- hdu 4317 Unfair Nim(状态压缩DP)——2012 Multi-University Training Contest 2
- HDU Problem k-dp
- hdu4284之状态压缩dp
- hdu3502,状态压缩dp
- HDU Problem p-dp
- hdu 1074 Doing Homework (状态压缩 dp)
- HDU - 4529 郑厂长系列故事――N骑士问题 (状态压缩DP)