您的位置:首页 > 其它

递推、错排公式

2012-05-09 18:31 996 查看
以前刚接触ACM时做11页,有挺多题不懂的。最近据某人说校纳新赛和杭电11页差不多,于是顺便又回来补上,收获不少,对递推有了更深的理解.

SolvedPro.IDTitleAuthorSource(AC/Submit)Ratio

2044一只小蜜蜂...lcy递推求解专题练习(For Beginner)(7342/19929)36.84%

2045不容易系列之(3)—— LELE的RPG难题lcy递推求解专题练习(For Beginner)(6245/15736)39.69%

2046骨牌铺方格lcy递推求解专题练习(For Beginner)(7318/15227)48.06%

2047阿牛的EOF牛肉串lcy递推求解专题练习(For Beginner)(5338/11408)46.79%

2048神、上帝以及老天爷lcy递推求解专题练习(For Beginner)(5231/12304)42.51%

2049不容易系列之(4)——考新郎lcy递推求解专题练习(For Beginner)(4456/11745)37.94%

2050折线分割平面lcy递推求解专题练习(For Beginner)(6391/9090)70.31%
2045 ( 不容易系列之(3)—— LELE的RPG难题 )

#include<cstdio>
#define MAXN 52

__int64 arr[MAXN];

int main()
{
    int n,i;
     arr[1]=3,arr[2]=6,arr[3]=6;
     for(i=4; i<MAXN; ++i)
         arr[i]=arr[i-1]+2*arr[i-2];
/*
arr[i]=arr[i-1]+2*arr[i-2];

在arr[i]时,可以由arr[i-1]和arr[i-2]得到,

arr[i-1]:  由于arr[i-1]和arr[1]不一样,所以arr[i]只能选择一种(arr[i]和arr[i-1]相邻且要和arr[0]不同)

arr[i-2]:  这时arr[i-1]不是最后一个,所以这个位置可以选两种颜色(只要和arr[i-2]不同就行了),
	       选好后arr[i]就只能选一种。

 */
    while(scanf("%d",&n)==1){
        printf("%I64d\n",arr
);
    }
    return 0;
}


2046 ( 骨牌铺方格

#include<cstdio>
#define MAXN 52
__int64 f[MAXN];

int main()
{ 
    int i,n;
    f[0]=0, f[1]=1, f[2]=2;
    for(i=3; i<MAXN; ++i)
        f[i] = f[i-1]+f[i-2];
/*
 f[i] = f[i-1]+f[i-2];

f[i-1]:  只能加一块竖着放的
f[i-2]:  两块横着叠在一起

两种都是只有一种情况
*/

    while(scanf("%d",&n)!=EOF){
        printf("%I64d\n",f
);
    }

    return 0;
}


2047
( 阿牛的EOF牛肉串 )

/*
对于一串字符,分为两种情况:

(1) 不以O结尾的, 如EF,那么它接下来有三种情况: EFF、EFE、EFO
	注意,有两个是不以O结尾的,一个是以O结尾的

(2) 以O结尾的,如EO,那么它接下来只有两种情况, EOF、EOE。
	且这两种情况都不以O结尾

那么可以推导出,对于某一次的情况,它以O结尾的个数是,上一次不以O结尾的个数
不以O结尾的个数是上一次 “不以O结尾的”的两倍 加上上次 “以O结尾的”的两倍。
可以得出递推方程

f1[i] = f2[i-1];              // f1保存以O结尾的个数
f2[i] = f1[i-1]*2+f2[i-1]*2;  // f2保存不以O结尾的个数

得出了这两个,总数也自然就求出来了
f[i] = f1[i]+f2[i];  // f保存总数

*/

#include<cstdio>
#define MAXN 52

__int64 f[MAXN],f1[MAXN],f2[MAXN];

int main()
{
    int n,i;
    f1[1]=1,f2[1]=2,f[1]=3;
    // f1为以 O 结尾的个数,f2为以E、F结尾的个数
    for(i=2; i<=40; ++i){
        f1[i] = f2[i-1];    
        f2[i] = f1[i-1]*2+f2[i-1]*2;

        f[i] = f1[i]+f2[i];
    }
    while(scanf("%d",&n)==1){
        printf("%I64d\n",f
);
    }
    
    return 0;
}


错排公式(1462,2048,2049):

某人写了n封信和n个信封,如果所有的信都装错了信封。求所有的信都装错信封,共有多少种不同情况。
分析思路:
1、当N=1和2时,易得解~,假设F(N-1)和F(N-2)已经得到,重点分析下面的情况:
2、当有N封信的时候,前面N-1封信可以有N-1或者 N-2封错装
3、前者,对于每种错装,可从N-1封信中任意取一封和第N封错装,故=F(N-1)*(N-1)
4、后者简单,只能是没装错的那封和第N封交换信封,没装错的那封可以是前面N-1封中的任意一个,故= F(N-2) * (N-1)

基本形式:d[1]=0; d[2]=1

递归式:d
= (n-1)*( d[n-1] + d[n-2])


这就是著名的错排公式。



2048
( 神、上帝以及老天爷 )


/*
错排公式

全部抽错的概率,即全部排错的情况个数除与的全排列个数

*/

#include<cstdio>
#define MAXN 52

__int64 f[MAXN],f1[MAXN],f2[MAXN];
double ans[MAXN];

int main()
{
    int C,n,i;
    f[1]=0,f[2]=1;

    __int64 sum=2;
    ans[2]=0.5;
    for(i=3; i<=20; ++i){
        sum *= i;
        f[i] = (i-1)*(f[i-1]+f[i-2]);
        ans[i] = f[i]*1.0/sum;
    }
    scanf("%d",&C);
    while(C--){
        scanf("%d",&n);
        printf("%.2f%%\n",ans
*100);
    }  
    return 0;
}




—— 生命的意义,在于赋予它意义。


原创 http://blog.csdn.net/shuangde800 , By
D_Double
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: