【Poj2825】Perfect Permutation 构造

来源:互联网 发布:ctos 软件 编辑:程序博客网 时间:2024/06/06 12:28

ORZ 。。。UOJ群里面的各位大爷。。。

当时关注这道题主要是因为准备Pkusc的考试。。。然而只会爆搜心塞了我一个星期QAQ

这道题找规律的困难点在于存再多解,并且解的数目非常非常多所以搜起来肉眼基本找不出规律

但是如果知道解答验证起来还是非常容易。。。

当n=4k+2或4k+3时无解
当n=4k时,构造数列:2k+1, [4k ~ 3k+2], [3k ~ 2k+2], [2k ~ k+1], 3k+1, [k ~ 1]
当n=4k+1时,将4k时的数列第一项改成4k+1, 最后加一项2k+1

贴两份代码,一份是N在300以下可以出(但是一些数字会非常慢)的信仰爆搜(搜的时候是按照绝对值的条件由大到小来的,因为绝对值越大存在的方案就越少,比如绝对值等于N-1就只有“1填到N”和“N填到1”两种情况,比普通爆搜快很多),另一份是AC代码。

#include<cstdlib>#include<cstdio>#include<iostream>#include<cstring>#include<cmath>#include<algorithm>#include<queue>#include<vector>using namespace std;#define MAXN 1005int N;int v[MAXN],A[MAXN];bool run(int now)//now就是现在需要满足的绝对值条件{if(now==-1)return true;else{for(int i=1;i<=N;i++)if(!A[i]){if(i-now>=1 && i-now<=N){if(!v[i-now]){v[i-now]=true;A[i]=i-now;if(run(now-1))return true;A[i]=0; v[i-now]=false;}}if(i+now>=1 && i+now<=N){if(!v[i+now]){v[i+now]=true;A[i]=i+now;if(run(now-1))return true;A[i]=0; v[i+now]=false;}}}return false;}}int main(){while(scanf("%d",&N)==1){for(int i=0;i<=N;i++)v[i]=0;memset(A,0,sizeof(A));if(N%4==0){run(N-1);for(int i=1;i<=N;i++)printf("%d ",A[i]);putchar('\n');}else if(N%4==1){run(N-1);for(int i=1;i<=N;i++)printf("%d ",A[i]);putchar('\n');}else{printf("0\n");}}return 0;}

#include<cstdlib>#include<cstdio>#include<iostream>#include<cstring>#include<cmath>#include<algorithm>#include<queue>#include<vector>using namespace std;int main(){int N,k;while(scanf("%d",&N)==1){if(N%4==0){k=N/4;printf("%d ",2*k+1);for(int i=4*k;i>=3*k+2;i--)printf("%d ",i);for(int i=3*k;i>=2*k+2;i--)printf("%d ",i);for(int i=2*k;i>=k+1;i--)printf("%d ",i);printf("%d ",3*k+1);for(int i=k;i>=1;i--)printf("%d ",i);}else if(N%4==1){k=(N-1)/4;printf("%d ",4*k+1);for(int i=4*k;i>=3*k+2;i--)printf("%d ",i);for(int i=3*k;i>=2*k+2;i--)printf("%d ",i);for(int i=2*k;i>=k+1;i--)printf("%d ",i);if(k)printf("%d ",3*k+1);for(int i=k;i>=1;i--)printf("%d ",i);if(k)printf("%d ",2*k+1);}else{printf("0");}putchar('\n');}return 0;}



0 0
原创粉丝点击