这个题的搜索可以打到48分……

#include <cstdio>
#include <cstring>
#include <algorithm>
const int N=;
bool must[N],in[N];
int cnt;
int n,a[N][N],q[N],b[N];
inline bool judge(int len,int lim){
return lim-len>=cnt;
}
inline bool check(int len){
register int i,j,k,pos,g;
register bool can;
for(i=;i<=n;++i){
can=false;
for(j=;j<=len;++j){
if(len-j+>=a[i][]){
pos=,g=;
for(k=j;k<=len;++k){
if(in[q[k]])continue;
if(q[k]!=a[i][pos+]){g=-;break;}
b[++pos]=q[k];
in[q[k]]=true;
}
can=g!=-&&pos==a[i][];
while(pos--)in[b[pos+]]=false;
if(can)break;
}
if(j>=a[i][]){
pos=,g=;
for(k=j;k>;--k){
if(in[q[k]])continue;
if(q[k]!=a[i][pos+]){g=-;break;}
b[++pos]=q[k];
in[q[k]]=true;
}
can=g!=-&&pos==a[i][];
while(pos--)in[b[pos+]]=false;
if(can)break;
}
}
if(!can)return false;
}
return true;
}
inline bool dfs(int pos,int lim){
if(!judge(pos-,lim))return false;
if(pos==lim+)return check(pos-);
register int i;
register bool keep;
for(i=;i<=;++i)
if(i!=q[pos-]){
q[pos]=i;
if(must[i]){
must[i]=false,--cnt;
keep=true;
}else keep=false;
if(dfs(pos+,lim))return true;
if(keep)must[i]=true,++cnt;
}
return false;
}
int main(){
//freopen("rio.in","r",stdin);
scanf("%d",&n);
register int i,j;
for(i=;i<=n;++i){
while(true){
scanf("%d",&j);
if(!j)break;
a[i][++a[i][]]=j;
must[j]=true;
}
}
for(i=;i<=;++i)
cnt+=must[i];
for(i=cnt;i<=;++i){
if(cnt<&&i==)break;
if(dfs(,i)){
printf("%d\n",i);
return ;
}
}
puts("-1");
return ;
}

Kod

搜索的时候减枝实在是太重要了,其次梦想与搜索之间的平衡也是很重要的,但是一定要合理且适当.
正解很神.
贴一发题解:

还有一位大佬的代码注释也很好:https://loj.ac/submission/66283
我就是看的这两个资料,然后码出来的.(把写法从spfa改成记忆化dfs会快3倍……)
在这里说一下坑吧,就是正着走的状态可以在半截出现,倒着走的状态可以在半截消失.
分享一下代码.
正着走的单向40分:

#include <cstdio>
#include <cstring>
#include <algorithm>
const int N=;
const int F=;
const int Inf=0x3f3f3f3f;
int n,ans,full,bit[N],a[N][N],l[N],b[N];
int f[N][N][F];
bool ex[N][N],can[N][N][N],in[N],fin[N][N][F];
inline bool check(int id,int len,int to){
register int i,pos=;
memset(in,,sizeof(in));
for(i=;i<=len;++i)
in[a[id][i]]=true;
for(i=;i<=l[to];++i){
if(in[a[to][i]])continue;
b[++pos]=a[to][i];
in[a[to][i]]=true;
}
if(pos!=l[id]-len)return false;
for(i=len+;i<=l[id];++i)
if(a[id][i]!=b[i-len])
return false;
return true;
}
inline void dfs(int id,int pos,int st){
//printf("%d %d %d\n",id,pos,st);
if(fin[id][pos][st]){
//puts("GG");
ans=std::min(ans,f[id][pos][st]);
return;
}
register int i;
for(i=;i<=n;++i)
if(i!=id&&(bit[i]&st)==)
if(can[id][pos][i]&&f[i][][st|bit[id]]>f[id][pos][st]){
f[i][][st|bit[id]]=f[id][pos][st];
dfs(i,,st|bit[id]);
}
if(pos!=l[id]&&f[id][pos+][st]>f[id][pos][st]+){
f[id][pos+][st]=f[id][pos][st]+;
dfs(id,pos+,st);
}
}
int main(){
//freopen("rio.in","r",stdin);
scanf("%d",&n);
full=(<<n)-;
register int i,j,k;
for(i=;i<=n;++i){
bit[i]=<<(i-);
while(true){
scanf("%d",&j);
if(!j)break;
a[i][++l[i]]=j;
ex[i][j]=true;
}
}
for(i=;i<=n;++i)
for(j=;j<=l[i];++j)
for(k=;k<=n;++k)
can[i][j][k]=check(i,j,k);
memset(f,0x3f,sizeof(f));
ans=Inf;
for(i=;i<=n;++i)
fin[i][l[i]][full^bit[i]]=true;
for(i=;i<=n;++i){
f[i][][]=;
dfs(i,,);
}
printf("%d\n",ans==Inf?-:ans);
return ;
}

Kod

倒着走的单向40分:

#include <cstdio>
#include <cstring>
#include <algorithm>
const int N=;
const int F=;
const int Inf=0x3f3f3f3f;
int n,ans,full,bit[N],a[N][N],l[N],b[N];
int f[N][N][F];
bool can[N][N][N],in[N],fin[N][N][F];
inline bool check(int id,int len,int to){
register int i,pos=;
memset(in,,sizeof(in));
for(i=;i<=len;++i)
in[a[id][i]]=true;
for(i=;i<=l[to];++i){
if(in[a[to][i]])continue;
b[++pos]=a[to][i];
in[a[to][i]]=true;
}
if(pos!=l[id]-len)return false;
for(i=len+;i<=l[id];++i)
if(a[id][i]!=b[i-len])
return false;
return true;
}
inline void dfs(int id,int pos,int st){
//printf("%d %d %d\n",id,pos,st);
if(fin[id][pos][st]){
//puts("GG");
ans=std::min(ans,f[id][pos][st]);
return;
}
if(!pos){
register int i,j;
for(i=;i<=n;++i)
if(i!=id&&(bit[i]&st)==)
for(j=;j<=l[i];++j)
if(can[i][j][id]&&f[i][j][st|bit[id]]>f[id][pos][st]){
f[i][j][st|bit[id]]=f[id][pos][st];
dfs(i,j,st|bit[id]);
}
}
if(pos&&f[id][pos-][st]>f[id][pos][st]+){
f[id][pos-][st]=f[id][pos][st]+;
dfs(id,pos-,st);
}
}
int main(){
//freopen("rio.in","r",stdin);
scanf("%d",&n);
full=(<<n)-;
register int i,j,k;
for(i=;i<=n;++i){
bit[i]=<<(i-);
while(true){
scanf("%d",&j);
if(!j)break;
a[i][++l[i]]=j;
}
}
for(i=;i<=n;++i)
for(j=;j<=l[i];++j)
for(k=;k<=n;++k)
can[i][j][k]=check(i,j,k);
memset(f,0x3f,sizeof(f));
ans=Inf;
for(i=;i<=n;++i)
fin[i][][full^bit[i]]=true;
for(i=;i<=n;++i){
f[i][l[i]][]=;
dfs(i,l[i],);
}
printf("%d\n",ans==Inf?-:ans);
return ;
}

Kod

经过我不断修改的清真美丽100分代码:

#include <set>
#include <cstdio>
#include <cstring>
#include <algorithm>
typedef long long LL;
std::set<LL> ext;
const int N=;
const int F=;
const int Inf=0x3f3f3f3f;
int n,full,bit[N],a[N][N],l[N];
int f[N][N][N][N][F];
bool ex[N][N][N],can[N][N][N],in[N],vis[N][N][N][N][F];
inline bool check(int id,int len,int to){
int i,pos=;
memcpy(in,ex[id][len],sizeof(in));
for(i=;i<=l[to];++i){
if(in[a[to][i]])continue;
++pos,in[a[to][i]]=true;
if(a[to][i]!=a[id][len+pos])
return false;
}
if(pos!=l[id]-len)return false;
return true;
}
inline void Init(){
scanf("%d",&n);
int i,j,k;
LL key;
for(i=;i<=n;++i){
l[i]=,key=;
memset(ex[i],,sizeof(ex[i]));
bit[i]=<<(i-),j=;
while(j){
scanf("%d",&j);
key=key*+j;
a[i][++l[i]]=j;
for(k=;k<=l[i];++k)
if(a[i][k])
ex[i][l[i]][a[i][k]]=true;
}
--l[i];
if(ext.count(key))--i,--n;
ext.insert(key);
}
full=(<<n)-;
for(i=;i<=n;++i){
can[][][i]=true;
for(j=;j<=l[i];++j)
for(k=;k<=n;++k)
can[i][j][k]=check(i,j,k);
}
memset(f,0x3f,sizeof(f));
}
#define cover(id1,pos1,id2,pos2,st,add) (k=std::min(dfs(id1,pos1,id2,pos2,st)+add,k))
inline int dfs(int id1,int pos1,int id2,int pos2,int st){
if(st==full&&pos1==l[id1]&&!pos2)return ;
int i,j,&k=f[id1][pos1][id2][pos2][st];
if(vis[id1][pos1][id2][pos2][st])return k;
vis[id1][pos1][id2][pos2][st]=true;
if(id2&&!pos2){
for(i=;i<=n;++i)
if(i!=id1&&!(bit[i]&st))
for(j=;j<=l[i];++j)
if(can[i][j][id2])
cover(id1,pos1,i,j,st|bit[i],);
}
for(i=;i<=n;++i)
if(can[id1][pos1][i]&&!(bit[i]&st))
cover(i,,id2,pos2,st|bit[i],);
if(pos1==l[id1]&&!pos2)return k;
if(pos1!=l[id1]&&(ex[id2][pos2+][a[id1][pos1+]]||!id2))
cover(id1,pos1+,id2,pos2,st,);
if(pos2&&(ex[id1][pos1][a[id2][pos2]]||!id1))
cover(id1,pos1,id2,pos2-,st,);
if(pos1!=l[id1]&&pos2&&a[id2][pos2]==a[id1][pos1+])
cover(id1,pos1+,id2,pos2-,st,);
return k;
}
inline void Work(){
int i,ans=Inf;
for(i=;i<=n;++i)
ans=std::min(dfs(,,i,l[i],bit[i]),ans);
printf("%d\n",ans==Inf?-:ans);
}
int main(){
Init(),Work();
return ;
}

Kod

我第一次A掉的时候写的100分(这个代码又臭又长又屎):

#include <cstdio>
#include <cstring>
#include <algorithm>
const int N=;
const int F=;
const int Inf=0x3f3f3f3f;
int n,ans,full,bit[N],a[N][N],l[N],b[N];
int f[N][N][N][N][F];
bool ex[N][N][N],can[N][N][N],in[N],fin[N][N][N][N][F];
inline bool check(int id,int len,int to){
register int i,pos=;
memset(in,,sizeof(in));
for(i=;i<=len;++i)
in[a[id][i]]=true;
for(i=;i<=l[to];++i){
if(in[a[to][i]])continue;
b[++pos]=a[to][i];
in[a[to][i]]=true;
}
if(pos!=l[id]-len)return false;
for(i=len+;i<=l[id];++i)
if(a[id][i]!=b[i-len])
return false;
return true;
}
inline void dfs(int id1,int pos1,int id2,int pos2,int st){
//printf("%d %d %d %d %d\n",id1,pos1,id2,pos2,st);
if(fin[id1][pos1][id2][pos2][st]){
//puts("GG");
ans=std::min(ans,f[id1][pos1][id2][pos2][st]);
return;
}
if(id2&&!pos2){
register int i,j;
for(i=;i<=n;++i)
if(i!=id1&&i!=id2&&(bit[i]&st)==)
for(j=;j<=l[i];++j)
if(can[i][j][id2]&&f[id1][pos1][i][j][st|bit[id2]]>f[id1][pos1][id2][pos2][st]){
f[id1][pos1][i][j][st|bit[id2]]=f[id1][pos1][id2][pos2][st];
dfs(id1,pos1,i,j,st|bit[id2]);
}
if(id1){
if(f[id1][pos1][][][st|bit[id2]]>f[id1][pos1][id2][pos2][st]){
f[id1][pos1][][][st|bit[id2]]=f[id1][pos1][id2][pos2][st];
dfs(id1,pos1,,,st|bit[id2]);
}
}else{
for(i=;i<=n;++i)
if(i!=id2&&(bit[i]&st)==&&f[i][][][][st|bit[id2]]>f[id1][pos1][id2][pos2][st]){
f[i][][][][st|bit[id2]]=f[id1][pos1][id2][pos2][st];
dfs(i,,,,st|bit[id2]);
}
}
}
if(id1){
register int i;
for(i=;i<=n;++i)
if(i!=id1&&i!=id2&&(bit[i]&st)==)
if(can[id1][pos1][i]&&f[i][][id2][pos2][st|bit[id1]]>f[id1][pos1][id2][pos2][st]){
f[i][][id2][pos2][st|bit[id1]]=f[id1][pos1][id2][pos2][st];
dfs(i,,id2,pos2,st|bit[id1]);
}
}else{
register int i;
for(i=;i<=n;++i)
if(i!=id2&&(bit[i]&st)==&&f[i][][id2][pos2][st]>f[id1][pos1][id2][pos2][st]){
f[i][][id2][pos2][st]=f[id1][pos1][id2][pos2][st];
dfs(i,,id2,pos2,st);
}
}
if((id2==||pos2==)&&(id1==||pos1==l[id1]))return;
if(id1&&pos1!=l[id1]&&(ex[id2][pos2+][a[id1][pos1+]]||!id2)&&f[id1][pos1+][id2][pos2][st]>f[id1][pos1][id2][pos2][st]+){
f[id1][pos1+][id2][pos2][st]=f[id1][pos1][id2][pos2][st]+;
dfs(id1,pos1+,id2,pos2,st);
}
if(id2&&pos2&&(ex[id1][pos1+][a[id2][pos2]]||!id1)&&f[id1][pos1][id2][pos2-][st]>f[id1][pos1][id2][pos2][st]+){
f[id1][pos1][id2][pos2-][st]=f[id1][pos1][id2][pos2][st]+;
dfs(id1,pos1,id2,pos2-,st);
}
//printf("<>%d %d %d %d %d\n",id1,pos1,id2,pos2,st);
if(id1&&id2&&pos2&&pos1!=l[id1]&&a[id2][pos2]==a[id1][pos1+]&&f[id1][pos1+][id2][pos2-][st]>f[id1][pos1][id2][pos2][st]+){
//puts("OK");
f[id1][pos1+][id2][pos2-][st]=f[id1][pos1][id2][pos2][st]+;
dfs(id1,pos1+,id2,pos2-,st);
}
//else puts("NO");
}
int main(){
//freopen("rio.in","r",stdin);
//freopen("wq.out","w",stdout);
scanf("%d",&n),full=(<<n)-;
register int i,j,k;
for(i=;i<=n;++i){
bit[i]=<<(i-);
while(true){
scanf("%d",&j);
if(!j)break;
a[i][++l[i]]=j;
}
}
for(i=;i<=n;++i)
for(j=;j<=l[i];++j)
for(k=;k<=n;++k)
can[i][j][k]=check(i,j,k);
for(i=;i<=n;++i)
for(j=;j<=;++j)
for(k=;k<=j;++k)
ex[i][j][a[i][k]]=true;
memset(f,0x3f,sizeof(f));
ans=Inf;
for(i=;i<=n;++i){
for(j=;j<=n;++j){
if(i==j)continue;
fin[i][l[i]][j][][full^bit[i]^bit[j]]=true;
f[i][][j][l[j]][]=;
}
fin[i][l[i]][][][full^bit[i]]=true;
f[i][][][][]=;
fin[][][i][][full^bit[i]]=true;
f[][][i][l[i]][]=;
}
for(i=;i<=n;++i){
for(j=;j<=n;++j){
if(i==j)continue;
dfs(i,,j,l[j],);
}
dfs(i,,,,);
dfs(,,i,l[i],);
}
printf("%d\n",ans==Inf?-:ans);
return ;
}

Kod

我在这里说一下我对于这道题的解法的理解吧.
看到题解之后,就会发现这道题dp的状态定义很谜.我们先看正着走单向的,我们之所以这么定义,是因为最终方案也一定是这样构成的,这很好理解.再看倒着走的,同样,我们之所以这么定义,也是因为最终方案也一定是这样构成的.那么我们再看双向的状态,思考一下,发现也是这样的.那么我们这么转移就一定没有问题.而这神奇的状态设计从哪里来呢.我觉得,就是抓出题目给出的操作的性质——“远观不如近看”,让“近看”去满足“远观”,用“远观”去匹配“近看”,再加上增量构造的思路,就迸发出了这道题的状态以及转移.
现在以我的水平,我对于这道题的理解大概也就这么多,也许以后会有更好的理解把.利用状态压缩,以及对于特殊的问题,设计合理的状态,大概就是我从这道题里学到的宝贵的东西,对于设计状态,我还是摸不着头脑的.

LOJ #6037.「雅礼集训 2017 Day4」猜数列 状压dp的更多相关文章

  1. loj 6037 「雅礼集训 2017 Day4」猜数列 - 动态规划

    题目传送门 传送门 题目大意 有一个位置数列,给定$n$条线索,每条线索从某一个位置开始,一直向左或者向右走,每遇到一个还没有在线索中出现的数就将它加入线索,问最小的可能的数列长度. 依次从左到右考虑 ...

  2. Loj 6036 「雅礼集训 2017 Day4」编码 - 2-sat

    题目传送门 唯一的传送门 题目大意 给定$n$个串,每个串只包含 ' .问是否可能任意两个不同的串不满足一个是另一个的前缀. 2-sat的是显然的. 枚举每个通配符填0还是1,然后插入Trie树. 对 ...

  3. 2018.10.27 loj#6035. 「雅礼集训 2017 Day4」洗衣服(贪心+堆)

    传送门 显然的贪心题啊...考试没调出来10pts滚了妙的一啊 直接分别用堆贪心出洗完第iii件衣服需要的最少时间和晾完第iii件衣服需要的最少时间. 我们设第一个算出来的数组是aaa,第二个是bbb ...

  4. LOJ#6035. 「雅礼集训 2017 Day4」洗衣服

    传送门 先处理出每一件衣服最早什么时候洗完,堆+贪心即可 然后同样处理出每件衣服最早什么时候烘干 然后倒序相加取最大值 # include <bits/stdc++.h> using na ...

  5. LOJ #6035.「雅礼集训 2017 Day4」洗衣服 贪心

    这道题的贪心好迷啊~我们对于两个过程进行单独贪心,然后再翻转一个,把这两个拼起来.先说一下单独贪心,单独贪心的话就是用一个堆,每次取出最小的,并且把这个最小的加上他单次的,再放进去.这样,我们得到的结 ...

  6. LOJ #6036.「雅礼集训 2017 Day4」编码 Trie树上2-sat

    记得之前做过几道2-sat裸体,以及几道2-sat前缀优化建图,这道题使用了前缀树上前缀树优化建图.我们暴力建图肯定是n^2级别的,那么我们要是想让边数少点,就得使用一些骚操作.我们观察我们的限制条件 ...

  7. loj #6032. 「雅礼集训 2017 Day2」水箱 线段树优化DP转移

    $ \color{#0066ff}{ 题目描述 }$ 给出一个长度为 \(n\) 宽度为 \(1\) ,高度无限的水箱,有 \(n-1\) 个挡板将其分为 \(n\) 个 \(1 - 1\) 的小格, ...

  8. [LOJ 6031]「雅礼集训 2017 Day1」字符串

    [LOJ 6031] 「雅礼集训 2017 Day1」字符串 题意 给定一个长度为 \(n\) 的字符串 \(s\), \(m\) 对 \((l_i,r_i)\), 回答 \(q\) 个询问. 每个询 ...

  9. [LOJ 6030]「雅礼集训 2017 Day1」矩阵

    [LOJ 6030] 「雅礼集训 2017 Day1」矩阵 题意 给定一个 \(n\times n\) 的 01 矩阵, 每次操作可以将一行转置后赋值给某一列, 问最少几次操作能让矩阵全为 1. 无解 ...

随机推荐

  1. https双向认证网站搭建

    新建网站 在搭建网站证书之前,我们先搭建好我们的网站 1.网站基本搭建 为我们的项目新建一个网站,按照如下的步骤来 1,打开IIS,右键单击网站弹出菜单,选择网站(如图1.1.1) 图1.1.1 2, ...

  2. Javac提示不是内部或外部命令

    1.先去百度搜索"jdk下载"下载最新版jdk,并安装,安装目录不用去更改,直接默认就好,下载完了之后,双击打开安装,jdk安装完成后,会接着安装jre包,(jre和jdk是配对的 ...

  3. WebGL射线拾取模型——八叉树优化

    经过前面2篇WebGL射线拾取模型的文章,相信大家对射线和模型面片相交的原理已经有所了解,那么今天我们再深入探究关于射线拾取的一个问题,那就是遍历场景中的所有与射线相交的模型的优化问题.首先我们来复习 ...

  4. linux ——使用find如何快速替换所有相同参数

    在生成环境上有时候需要大规模修改某一配置里的参数,但是该参数存在多个地方,比如IP地址 端口 项目名等,特别是项目名称混乱想统一 find  /项目地址 -type f |xargs grep &qu ...

  5. #Ubuntu 18.04 安装tensorflow-gpu 1.9

    参考 https://tensorflow.google.cn/install/install_linux http://nvidia.com/cuda http://developer.nvidia ...

  6. 【转载】windows安装python2.7后的注册表问题

    原文出自:https://www.cnblogs.com/tlz888/p/6879227.html [提要]win平台上,python2.7官网的安装包在安装后不会添加环境变量且不会把安装信息写入注 ...

  7. loadrunner socket协议问题归纳(5)

    获取服务器的返回值,可以用web_reg_save_param函数,该参数最好放到: 语法: int web_reg_save_param(const char *ParamName, <lis ...

  8. AngularJS学习之数据绑定

    既然AngularJS是以数据作为驱动的MVC框架,在上一篇文章中,也介绍了AngularJS如何实现MVC模式的,所有模型里面的数据,都必须经过控制器,才能展示到视图中. 什么是数据绑定 首先来回忆 ...

  9. 超级迷宫需求分析与建议-NABCD模型

    超级迷宫需求分析与建议-NABCD模型 制作者-姜中希 1N-Need 需求  首先这是一个手机游戏风靡的时代,随着智能手机不断的更新问世,4G网络的不断扩大普及,越来越多的手机游戏受到广大玩家的追捧 ...

  10. is-A继承?Has-A?

    教程把is-A和Has-A放在一起,我还以为java支持简单的方法能把Has对象的方法导出呢..   extents  implements 要试一下. 不知道狗和汽车为什么总是被选出来举例.   p ...