1979: #6037. 「雅礼集训 2017 Day4」猜数列

题目描述

有一个长度为 m mm 的,由 1 11 到 9 99 之间的数构成的未知数列 am a_mam。

你现在有 n nn 个线索,每个线索都是用如下方式生成的:

  • 选择序列 am a_mam 的某一个位置 p pp 作为开始;
  • 选择某个方向(向左或向右);
  • 从 p pp 出发往你选择的方向走,每遇到一个之前未出现的数就将它加到线索中。

(可以发现,每条线索的长度都不超过 9 99。)
现在你需要求出满足所有线索的长度最小的序列的长度。

输入

第一行一个整数 n nn,表示线索的数量。
接下来 n nn 行,每行有若干个以 0 00 结尾的整数,表示一条线索。

输出

如果无解请输出 −1 -1−1,否则输出可能的最小长度。

样例输入 

5
1 2 0
3 4 0
1 4 3 0
3 1 4 2 0
1 2 4 3 0

样例输出 

7

提示

对于 20% 20\%20% 的数据,答案不超过 10 1010;
对于另外 40% 40\%40% 的数据,保证存在一个解,使得所有线索都可以通过从某个位置向右遍历得到;
对于 100% 100\%100% 的数据,1≤n≤10 1 \leq n \leq 101≤n≤10。

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
int rd(){
    int x=0,flg=1;
    char c=getchar();
    for (;(c<48||c>57)&&c!='-';c=getchar());
    if (c=='-') flg=-1,c=getchar();
    for (;c>47&&c<58;x=x*10+c-48,c=getchar());
    return flg*x;
}
int n,m,len[11],a[11][11],b[11][11],g[11][11][11],f[11][11][11][11][1024];
bool check(int i,int j,int x){
    for (int k=0;k<len[x];++k)
        if (j<len[i]&&b[i][a[x][k]]==j) ++j;
        else if (b[i][a[x][k]]>j) return 0;
    return j==len[i];
}
int dfs(int l,int x,int r,int y,int s){
    if (!x&&y==len[r]&&s==(1<<n)-1) return 0;
    if (f[l][x][r][y][s]!=-1) return f[l][x][r][y][s];
    int ret=0x3f3f3f3f;
    if (l<n&&!x){
        for (int i=0;i<n;++i)
            if (!(s>>i&1))
                for (int j=0;j<len[i];++j)
                    if (g[i][j][l]) ret=min(ret,dfs(i,j,r,y,s|1<<i));
        ret=min(ret,dfs(n,0,r,y,s));
    }
    for (int i=0;i<n;++i)
        if (!(s>>i&1)&&g[r][y][i])
            ret=min(ret,dfs(l,x,i,0,s|1<<i));
    for (int i=1;i<10;++i){
        int fl=x&&a[l][x-1]==i,fr=y<len[r]&&a[r][y]==i;
        if (fl&&fr) ret=min(ret,dfs(l,x-1,r,y+1,s)+1);
        if (fl&&b[r][i]<=y) ret=min(ret,dfs(l,x-1,r,y,s)+1);
        if (fr&&b[l][i]<=x) ret=min(ret,dfs(l,x,r,y+1,s)+1);
    }
    f[l][x][r][y][s]=ret;
    return ret;
}
int main()
{
    n=rd();
    memset(b,0x3f,sizeof(b));
    for (int i=0,j,x;i<n;len[i]=j,++i)
        for (j=0,x=rd();x;++j,x=rd()) a[i][j]=x,b[i][x]=j;
    for (int i=1;i<10;++i) b[n][i]=0;
    for (int i=0;i<n;++i)
        for (int j=0;j<len[i];++j)
            for (int x=0;x<n;++x) g[i][j][x]=check(i,j,x);
    for (int i=0;i<n;++i)
        g[i][0][n]=1,g[n][0][i]=1;
    memset(f,-1,sizeof(f));
    int ans=0x3f3f3f3f;
    for (int i=0;i<n;++i)
        ans=min(ans,dfs(i,len[i],n,0,1<<i));
    printf("%d\n",ans>100?-1:ans);
    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值