[jzoj]1261. 数字游戏(搜索+剪枝)

来源:互联网 发布:淘宝被恶意差评怎么办 编辑:程序博客网 时间:2024/06/06 03:41

Description

Charles和sunny在玩一个简单的游戏。若给出1~n的一个排列A,则将A1、A2相加,A2、A3相加……An-1、An相加,则得到一组n-1个元素的数列B;再将B1、B2相加,B2、B3相加,Bn-2、Bn-1相加,则得到一组n-2个元素的数列……如此往复,最终会得出一个数T。而Charles和sunny玩的游戏便是,Charles给出n和T,sunny在尽可能短的时间内,找到能通过上述操作得到T且字典序最小的1~n的排列。(sunny大声说:“What an easy game!”,接着几下就给出了解),Charles觉得没意思,就想和你玩,当然,你可以用一种叫做“电子计算机”的东西帮你。

Input

本题有多组数据,对于每组数据:一行两个整数n(0< n<=20),t即最后求出来的数。两个0表示输入结束。

Output

对于每组测试数据输出一行n个整数,用空格分开,行尾无多余空格,表示求出来的满足要求的1~n的一个排列。

Sample Input

4 16
3 9
0 0

Sample Output

3 1 2 4
1 3 2

Data Constraint

Hint

【样例说明】
开始排列: 3 1 2 4
第一次操作:3+1=4 1+2=3 2+4=6
得到: 4 3 6
第二次得到: 7 9
最后就是: 16
【注释】
数据保证有解。
对于30%的数据,保证该组里的每个N都不超过10。
对于100%的数据,保证有每个N不超过20,且每组数据的个数不超过10。


Solution

暴力很显然会超时.

优化一、系数

我们知道原本序列的A,到最终序列T,每一个数其实都乘上了一个对应的系数,这个系数可以预处理.

优化二、对称性

题目要求字典序最小,我们知道系数是有对称性的,所以当两个对称的x,y,有a[y]

#include <iostream>#include <cstdio>#include <cstring>#include <cstdlib>using namespace std;int n,t,i,j,k,maxmax,minmin,l1,l2,kk,len;int a[21][21][21];int s[21],d[21],x[21],have[21];bool bz[21],flag;void dfs(int k,int sum){           if (k>n)    {        if (sum==t)        {            for (j=1;j<=n-1;j++)                printf("%d ",x[j]);            printf("%d\n",x[n]);            flag=false;                     }               return;    }    if (sum+s[k]>t) return; //优化一-合法性.    if (sum+n*s[k]<t) return; //优化一-合法性.    kk=k; maxmax=minmin=len=0;    l1=(n+1)/2; l2=l1+1;        for (j=n;j>=1;j--)        if (bz[j]) have[++len]=j;    for (j=1;j<=len;j++)    {        if (l1<k) l1=0;        while (l2<k) l2++;        if (d[l1]>=d[l2]) maxmax+=d[l1]*have[j],minmin+=d[l1--]*have[len-j+1]; else maxmax+=d[l2]*have[j],minmin+=d[l2++]*have[len-j+1];            }    if (sum+maxmax<t)         return;    if (sum+minmin>t)         return;    int up;     if (k<=(n+1)>>1) up=1; else up=x[n-k+1]+1; //优化二-对称性     for (int i=up;i<=n;i++)        if ((bz[i])&&(flag))        {                       x[k]=i;            bz[i]=false;            dfs(k+1,sum+i*d[k]);            bz[i]=true;                 }}int main(){    freopen("easy.in","r",stdin);    freopen("easy.out","w",stdout);     scanf("%d%d",&n,&t);    memset(bz,1,sizeof(bz));    while (n+t>0){        memset(a,0,sizeof(a));        memset(d,0,sizeof(d));        for (i=1;i<=n;i++)            a[1][i][i]=1;        for (i=2;i<=n;i++)            for (j=i;j<=n;j++)                for (k=1;k<=n;k++)                    a[i][j][k]=a[i-1][j-1][k]+a[i-1][j][k];        for (k=1;k<=n;k++)            d[k]=a[n][n][k];  //优化三-系数        s[n+1]=1e8; s[n]=d[n];              for (k=n-1;k>=1;k--)            s[k]=s[k+1]+d[k];               flag=true;        dfs(1,0);        scanf("%d%d",&n,&t);    }}
原创粉丝点击