Gym 101343.J - Husam and the Broken Present 2(状压dp)
2017-10-24 12:19
441 查看
题意:给你n个(n≤15)序列连续片段,每个片段包括m个数字(m≤100)。最后问你构造一个数字序列,使得这n个串都是它的子串,这个序列的最短长度为多少。
思路:显然可以2^n枚举当前使用了哪些片段,然后显然这些串连成一串,那么需要再多一个维度来记录结尾的是哪个片段。dp[i][j]的方程雏形就有了。其次考虑到,方程的转移 需要记录两个段之间,至少添加几位,那么就是添加串的长度-两串前后缀公共部分。所以需要预处理。但是注意一个地方:完全包含的时候需要特判处理。
思路:显然可以2^n枚举当前使用了哪些片段,然后显然这些串连成一串,那么需要再多一个维度来记录结尾的是哪个片段。dp[i][j]的方程雏形就有了。其次考虑到,方程的转移 需要记录两个段之间,至少添加几位,那么就是添加串的长度-两串前后缀公共部分。所以需要预处理。但是注意一个地方:完全包含的时候需要特判处理。
#include <bits/stdc++.h> using namespace std; const int maxn = 100 + 5; const int INF = 0x3f3f3f3f; int a[20][maxn]; int cover[maxn][maxn];//i能否覆盖j int linkLen[maxn][maxn];//j接在i后面,两者最长公共部分 int dp[(1<<16) + 5][20]; int illegal[20]; bool checkCover(int i, int j, int st) { for(int k = 1; k <= a[j][0]; k++) { if(a[i][st + k - 1] != a[j][k]) return false; } return true; } int checkLink(int i, int j, int st) { int ret = 0; for(int k = 1; k <= a[j][0] && st + k - 1 <= a[i][0]; k++) { if(a[i][st + k - 1] == a[j][k]) ret++; else return 0; } return ret; } int main() { int n; scanf("%d", &n); for(int i = 0; i < n; i++) { scanf("%d", &a[i][0]); for(int j = 1; j <= a[i][0]; j++) scanf("%d", &a[i][j]); } //先检查是否包含。 memset(cover, 0, sizeof(cover)); for(int i = 0; i < n; i++) { for(int j = 0; j < n; j++) { if(illegal[i]) continue; if(i == j) continue; int leni = a[i][0], lenj = a[j][0]; if(leni < lenj) continue; for(int st = 1; st + lenj - 1 <= leni; st ++) { if(checkCover(i, j, st)) { cover[i][j] = 1; illegal[j] = 1; break; } } } } int cnt = 0; for(int i = 0; i < n; i++) { if(illegal[i]) continue; for(int j = 0; j <= a[i][0]; j++) a[cnt][j] = a[i][j]; cnt++; } n = cnt; // cout << " n = " << n << endl; //最长公共部分 memset(linkLen, 0, sizeof(linkLen)); for(int i = 0; i < n; i++) { for(int j = 0; j < n; j++) { if(i == j) continue; int len = 0; for(int st = 1; st <= a[i][0]; st++) { len = max(len, checkLink(i, j, st)); } linkLen[i][j] = len; // printf("linkLen[%d][%d] = %d\n", i, j, linkLen[i][j]); } } memset(dp, INF, sizeof(dp)); for(int i = 0; i < n; i++) dp[1 << i][i] = a[i][0]; for(int S = 0; S < (1 << n); S++) { for(int i = 0; i < n; i++) { if(S & (1 << i)) { for(int j = 0; j < n; j++) { if(i == j) continue; if(S & (1 << j)) continue; dp[S | (1 << j)][j] = min(dp[S][i] + a[j][0] - linkLen[i][j], dp[S | (1 << j)][j]); } } } } int ans = INF; for(int i = 0; i < n; i++) ans = min(ans, dp[(1 << n) - 1][i]); printf("%d\n", ans); return 0; }
相关文章推荐
- GYM 100694 L.Hanoi Towers and the Progress(dp)
- HDU 1028 Ignatius and the Princess III (母函数,或者DP)
- 【整数划分+DP】HDU_1028_D - Ignatius and the Princess III
- UVAlive 6560 - The Urge to Merge(状压dp)
- The King’s Ups and Downs hdu 4489 (递推dp)
- hdu1028 Ignatius and the Princess III(DP整数划分)
- poj 2282 Islands and Bridges(状压DP)
- poj 2441 Arrange the Bulls (状压dp)
- Codeforces Round #384 (Div. 2) E. Vladik and cards 状压dp
- codeforces 289B - Polo the Penguin and Matrix 二分+dp
- poj3311(Hie with the Pie)状压dp
- Codeforces Round #333 E. Kleofáš and the n-thlon (期望dp)
- poj2288(Islands and Bridges) 状压DP
- It is possible that this issue is resolved by uninstalling an existing version of the apk if it is present, and then re-installing ___Error Installing APK
- HDU1028 Ignatius and the Princess III(整数拆分:母函数||DP)
- [杂题 交互] Codeforces Gym 101190 NEERC 16 I. Indiana Jones and the Uniform Cave
- D - Ignatius and the Princess III(DP方法)
- HDU 1028 Ignatius and the Princess III (母函数 或 动态规划DP)
- bc #52 div 2 B || hdoj 5418 Victor and World(tsp问题,状压dp)
- HDU 3991 Harry Potter and the Present II 最小路径覆盖 建图