CF gym 101343 J Husam and the Broken Present 2

题目:Husam and the Broken Present 2

思路:
被其他串包含的串一定不会对答案造成影响,所以先把这些串去掉。
对于其他的串,可以预处理出两两之间的公共部分的长度,即第一个串的前缀和第二个串的后缀有多少公共部分。
令状态f[i][j]表示最后链接的是i串,其中j的串已被使用的最优结果。j是所有串是否被使用的01数组的二进制表示。
状态转移方程:
f[k][j|x]=min(f[k][j|x],f[i][j]+m[k]-g[i][k])
边界:
f[k][(1<<k-1)]=m[k]

代码:

#include<bits/stdc++.h>
using namespace std;

#define maxn 15
#define maxm 100
#define maxs (1<<16)
#define inf (1<<30)

int n;
int m[maxn+5]= {0};
vector<int> a[maxn+5];

int g[maxn+5][maxn+5]= {0};
int f[maxn+5][maxs+5]= {0};

void initf(int St) {
    for(int j=1; j<St; j++) {
        for(int i=1; i<=n; i++) {
            f[i][j]=(1<<30);
        }
    }
    for(int k=1; k<=n; k++) {
        f[k][(1<<k-1)]=m[k];
    }
}

int dp() {
    int St=(1<<n);
    initf(St);
    for(int j=1; j<St; j++) {
        for(int i=1; i<=n; i++) {
            if(!((1<<i-1)&j)) continue;
            for(int k=1; k<=n; k++) {
                int x=(1<<k-1);
                if(!(j&x)) {
                    f[k][j|x]=min(f[k][j|x],f[i][j]+m[k]-g[i][k]);
                }
            }
        }
    }
    int ans=inf;
    for(int i=1; i<=n; i++) {
        ans=min(f[i][(1<<n)-1],ans);
    }
    return ans;
}

void readin() {
    scanf("%d",&n);
    for(int i=1; i<=n; i++) {
        scanf("%d",&m[i]);
        for(int j=1; j<=m[i]; j++) {
            int x;
            scanf("%d",&x);
            a[i].push_back(x);
        }
    }
}

int findprefix(int y,int x) {
    int ans=0;
    for(int i=0; i<m[x]; i++) {
        int s=0;
        for(int j=m[y]-i-1;j<m[y];j++) {
            if(a[x][s]!=a[y][j]) goto T;
            s++;
        }
        ans=max(ans,s);
        T:;
    }
    return ans;
}

bool cnt[maxn+5]={0};

bool findh(int x,int y) {
    for(int i=0;i<m[y]-m[x];i++) {
        for(int j=0;j<m[x];j++){
            if(a[x][j]!=a[y][i+j]) goto F;
        }
        return true;
        F:;
    }
    return false;
}

void del(){
    for(int i=1;i<=n;i++) {
        if(!cnt[i]) continue;
        for(int j=i;j<=n;j++) {
            a[j]=a[j+1];
            cnt[j]=cnt[j+1];
            m[j]=m[j+1]; 
        }
        n--,i--;
    }
}

void init() {
    for(int i=1;i<=n;i++) {
        for(int j=1;j<=n;j++) {
            if(i==j||cnt[i]||cnt[j]) continue;
            if(m[i]>m[j]) continue;
            if(findh(i,j)) cnt[i]=1;
        }
    }
    del();
    for(int i=1; i<=n; i++) {
        for(int j=1; j<=n; j++) {
            if(j==i) continue;
            else g[i][j]=findprefix(i,j);
        }
    }
}

int main() {
    readin();
    init();
    int ans=dp();
    printf("%d",ans);
    return 0;
}

猜你喜欢

转载自blog.csdn.net/rabbit_ZAR/article/details/81413063