1. 程式人生 > ><gym101343J. Husam and the Broken Present 2> (狀壓DP)

<gym101343J. Husam and the Broken Present 2> (狀壓DP)

一起 names 都是 預處理 ret %d 註意 一個 size

題意:給定n個串 每個串長度不超過100

   找到一個新串 使得這n個串都是它的字串 輸出這個新串的最小長度

題解:n是15 n的階乘的復雜度肯定不行 就想到了2的15次方的復雜度

   想到了狀壓但是不知道怎麽維護 所以加一維就好了 dp[i][j]表示當前狀態為i 且末尾是第j個串

轉移簡直弱智 預處理val[i][j]表示第i個串和第j個串拼在一起會節省的長度 那麽答案最後就是總長度減去節省最大的長度了

   然後還要註意一下包含的問題 假如1 2 3,2 3 4 5和3 4這三個串3 4是被包含的

   但是你轉移的時候1 2 3和2 3 4 5接在一起後變成 1 2 3 4 5包含了3 4但是此時的狀態還是只用了第1個和第2個串的狀態

   所以把包含的串去重一下就好了... 弱智這都寫了四個小時

技術分享圖片
#include <bits/stdc++.h>
using namespace std;

int vis[20];
int num[20];
int q[20][105];
int val[20][20];
int dp[70000][20];

int main()
{
    int n;
    scanf("%d", &n);

    int ans = 0;
    for(int i = 1; i <= n; i++)
    {
        scanf("%d", &q[i][0]);
        
for(int j = 1; j <= q[i][0]; j++) scanf("%d", &q[i][j]); } for(int i = 1; i <= n; i++) vis[i] = 1; int cnt = 0; for(int i = 1; i <= n; i++) //去重 { if(!vis[i]) continue; for(int j = 1; j <= n; j++) { if(i == j) continue
; if(!vis[j]) continue; if(q[i][0] >= q[j][0]) { for(int k = 1; k + q[j][0] - 1 <= q[i][0]; k++) { bool f = true; for(int kk = 1; kk <= q[j][0]; kk++) { if(q[i][k + kk - 1] == q[j][kk]) continue; else {f = false; break;} } if(f) {vis[j] = 0; break;} } } } } for(int i = 1; i <= n; i++) if(vis[i]) cnt++; int zn = 0; for(int i = 1; i <= n; i++) if(vis[i]) num[++zn] = i; for(int i = 1; i <= zn; i++) { for(int j = 0; j <= q[num[i]][0]; j++) q[i][j] = q[num[i]][j]; ans += q[i][0]; } for(int i = 1; i <= cnt; i++) //預處理價值 { for(int j = 1; j <= cnt; j++) { if(i == j) continue; val[i][j] = 0; for(int k = 1; k <= q[i][0]; k++) { if(q[i][k] == q[j][1]) { bool f = true; for(int kk = 1; kk + k <= q[i][0]; kk++) { if(q[i][k + kk] == q[j][kk + 1]) continue; else { f = false; break;} } if(f) {val[i][j] = q[i][0] - k + 1; break;} } } } } memset(dp, 0, sizeof(dp)); int sta = (1 << cnt) - 1; for(int i = 0; i <= sta; i++) { memset(vis, 0, sizeof(vis)); for(int j = 0; j < n; j++) { int c = (i >> j) & 1; if(c == 1) vis[j + 1] = 1; } for(int j = 1; j <= n; j++) { if(vis[j]) continue; int v = (1 << (j - 1)); for(int k = 1; k <= n; k++) { if(!vis[k]) continue; dp[i + v][j] = max(dp[i + v][j], dp[i][k] + val[k][j]); } } } int zd = 0; for(int i = 1; i <= cnt; i++) zd = max(zd, dp[sta][i]); printf("%d\n", ans - zd); return 0; } /* 3 3 1 2 3 2 3 4 4 2 3 4 5 */
View Code

<gym101343J. Husam and the Broken Present 2> (狀壓DP)