[codeforces][gym101343J]Husam and the Broken Present 2

time limit per test:1.0 s
memory limit per test:256 MB

After you helped Husam and rebuilt his beautiful array a he became very happy. To avoid losing his array again, Husam made n copies from it, and distributed it to n of his friends. After that Husam became sure that he can rebuild the array a again if he lost it, so he destroyed the table t.

Today, Husam was looking for his array a a , but he was not able to find it. Husam visited all his n friends to take a copy from the array. Unfortunately, all his friends thought that the length of the array a was very long, so instead of keeping the array itself, each friend i take a subarray (li,ri) from the array and kept it in a safe place, and get rid of the rest of the array.

Now Husam has n subarrays from the array a a , but he cannot remember the original array or even its length. Husam now needs your help again, he will give you the n subarrays, and your task is to build a new array a such that it contains all the given subarrays inside it as subarrays, and its length must be as minimal as possible. Can you?

Input

The first line contains an integer n(1n15) n ( 1   ≤   n   ≤   15 ) , where n is the number of friends Husam has.

Then n lines follow, each line i begins with an integer mi(1mi100) m i ( 1   ≤   m i   ≤   100 ) , where mi is the length of the subarray the ith friend has. Then mi integers follow, representing the i i -th subarray. All values x in the subarrays are in the range (1x109).

Output

Print the minimal length of the new array a a , such that a contains all the given subarrays in the input inside it as subarrays.

Examples

Input

3
2 1 2
4 3 4 5 6
3 2 3 4

Output

6

Input

5
3 4 7 5
4 7 9 2 5
3 7 5 2
4 5 1 4 7
4 9 2 5 1

Output

9

Note

A subarray of the array a is a sequence al,al+1,...,ar for some integers (l,r) ( l ,   r ) such that (1lrn) ( 1   ≤   l   ≤   r   ≤   n ) .

In the first test case the array a a can be [1,2,3,4,5,6]. Its length is as minimal as possible, and it contains all the the given subarrays in the input inside it as subarrays.

题意:
询问n个数字串,让你生成一个新的串,使得新串包含所有的n个数字串,并且长度最短。

题解:
状压DP
去重,先将可以被其他数字串包含的数字串去掉。
状态 S S 当前生成的串表示包含了哪些数字串。
f[i][S]表示当前生成的串包含了 S S 状态里的所有串,并且生成的串结尾是第i个串
f[i][S]=min(f[j][S(1<<(i1))]+calc(b[j],b[i])) f [ i ] [ S ] = m i n ( f [ j ] [ S − ( 1 << ( i − 1 ) ) ] + c a l c ( b [ j ] , b [ i ] ) )
calc(b[j],b[i]) c a l c ( b [ j ] , b [ i ] ) 表示将 b[i] b [ i ] 串接在 b[j] b [ j ] 串的末尾,至少要增加多少长度。

#include<iostream>
#include<cstdio>
#include<cmath>
#include<cstring>
#include<algorithm>
#include<cstdlib>
#define LiangJiaJun main
#define ll long long
#define MOD 100000000
#define INF 1999122700
using namespace std;
int n;
struct Ds{
    int l;
    int x[104];
}a[24],b[24];
bool cont[24];
inline bool dex(Ds A,Ds B){
    return A.l>B.l;
}
bool nop(Ds A,Ds B){
     for(int i=1;i+B.l-1<=A.l;i++){
         bool ok=1;
         for(int j=1;j<=B.l;j++){
             if(A.x[i+j-1]!=B.x[j]){
                ok=0;
                break;
             }
         }
         if(ok)return 1;
     }
     return 0;
}
int cap(Ds A,Ds B){
    int ans=0;
    for(int i=1;i<=A.l;i++){
        if(B.x[1]==A.x[i]){
            bool ok=1;
            for(int j=1;i+j-1<=A.l;j++){
                if(B.x[j]!=A.x[i+j-1]){
                    ok=0;break;
                }
            }
            if(ok)ans=max(ans,A.l-i+1);
        }
    }
    return B.l-ans;
}
int f[24][(1<<15)+4];
int w33ha(){
    memset(cont,0,sizeof(cont));
    for(int i=1;i<=n;i++){
        scanf("%d",&a[i].l);
        for(int j=1;j<=a[i].l;j++)scanf("%d",&a[i].x[j]);
    }
    sort(a+1,a+n+1,dex);
    for(int i=1;i<=n;i++){
        for(int j=1;j<i;j++){
            if(cont[j])continue;
            if(nop(a[j],a[i])){
                cont[i]=1;
                break;
            }
        }
    }
    int cnt=0;
    for(int i=1;i<=n;i++){
        if(!cont[i])b[++cnt]=a[i];
    }
    for(int S=0;S<=(1<<cnt);S++){
        for(int i=0;i<=cnt;i++){
            f[i][S]=INF;
        }
    }
    for(int i=1;i<=cnt;i++){
        f[i][1<<(i-1)]=b[i].l;
    }
    f[0][0]=0;
    for(int S=1;S<(1<<cnt);S++){
        for(int i=1;i<=cnt;i++){
            if(!(S&(1<<(i-1))))continue;
            int S1=S-(1<<(i-1));
            for(int j=1;j<=cnt;j++){
                if(i==j)continue;
                if(!(S1&(1<<(j-1))))continue;
                f[i][S]=min(f[i][S],f[j][S1]+cap(b[j],b[i]));
            }
        }
    }
    int ans=INF;
    for(int i=1;i<=cnt;i++){
        ans=min(ans,f[i][(1<<cnt)-1]);
    }
    printf("%d\n",ans);
    return 0;
}
int LiangJiaJun(){
    while(scanf("%d",&n)!=EOF)w33ha();
    return 0;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值