YBTOJ 折纸问题

YBTOJ 折纸问题_第1张图片

思路分析:

先分析一下题意:通过翻转变换,让已知的纸条变为理想的纸条,求是否能实现。

看到题目的要求,很容易想到这道题要用 dfsdfsdfs。

数据范围:70 % 的数据 N <= 10 (良心啊)爆搜就能过。

100 %数据 : N <= 15 这就需要一点点技巧了。


解题技巧:

考虑操作的等效性,发现枚举翻折线时,只需要枚举前半部分的翻折线,因为当翻折线在后半部分的时候,就相当于先整体翻折,翻折线就到了前面。

最后统计答案的时候,考虑这个数组,如果回文序列和目标纸条相同也算可以做到。


代码+解释:

#include
using namespace std;
inline int read(){//快读不解释
    int x=0,f=1;char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch == '-') f=-1 ; ch=getchar();}
    while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+(ch^48) ; ch=getchar();}
    return x*f;
}
const int M = 1010;
int a[M],b[M];
int n,m;
bool dfs(int len,int *s){ // len表示当前数组的长度,s数组表示要被翻折的数组
    if(len == m){ //如果当前的长度和要匹配的长度相当,开始判断符不符合
        bool f1=1,f2=1; //别忘了是两个,回文相同也可以
        for(register int i(1) ; i<=m ; i=-~i){
            if(s[i] != b[i]){ //正着匹配,如果有不同的话,把f1标为false
                f1=0;
                break;
            }
        }
        for(register int i(1) ; i<=m ; i=-~i){
            if(s[len-i+1] != b[i]){ //反着匹配,也就是回文匹配,其余相同
                f2=0;
                break;
            }
        }
        if(f1 || f2) return 1; //如果两个中有一个能匹配,就表示可以,返回1
        return 0; //都不能的话返回0
    }
    bool ans=0; //表示能不能成功匹配
    int d[M]; //用来记录翻折后的数组
    for(register int i(1) ; i<=len-1 ; i=-~i){ //从1开始枚举翻折的位置
        if(len < m) continue; //如果此时的len已经小于m了,没有继续的必要了
        if(i <= len/2){ //翻折的位置在前半段
            for(register int j(1),k(len) ; k>=i+1 ; --k,j=-~j) 
                d[j] = s[k]; //模拟翻折过程,先把s翻折线后面的位置赋值
            for(register int j(len-i),k(i) ; k>=1 ; --k,--j) 
                d[j] += s[k]; //根据题目要求,把s剩下的数加到d的后几位中
        }
        else{ //翻折的位置在后半段
            for(register int j(1),k(1) ; k<=i ; k=-~k,j=-~j) 
                d[j] = s[k]; //同样,先把s的数组赋值给d
            for(register int j(i),k(i+1) ; k<=len ; k=-~k,--j) 
                d[j] += s[k]; //然后把s数组剩下的数加到d数组里面
        }

        //以上操作画个草图,模拟一下过程,很容易理解

        ans = ans | dfs(max(i,len-i),d); //注意要"|",有1则1
    }
    return ans; //最后返回能不能做到
}
signed main(){
    while(scanf("%d",&n)!=EOF){ //多组数据读入方法
        for(register int i(1) ; i<=n ; i=-~i) a[i] = read();
        m=read();
        for(register int i(1) ; i<=m ; i=-~i) b[i] = read();
        if(dfs(n,a)) printf("S\n"); //如果能通过翻折匹配,输出S
        else printf("N\n"); //不能的话输出N,别忘了换行
    }
    return 0; //完美收官
}

 

你可能感兴趣的:(蓝桥杯,c++,职场和发展,算法,深度优先)