三球排序不相邻,刷漆不相邻,错排

题目1:

1.长度为n的方格,刷3种颜色的颜料,相邻的方格颜料颜色不能相同,且首尾方格颜色不能相同。每个方格必须涂色。计算一共有多少种涂色方式。

思路:

递推公式,一共n个格子,要把子问题改成和整个问题条件一致,如果考虑选定第一个,此时最后一个有两种可能,子问题是前n-1个,这个时候第n-1个明显和第n个情况不同。这样无法地推。
所以考虑
1)选定第一个的时候,第n-1个的可能,如果他和第一个相同,则第n个可能性为2,第n-2个与第n-1个不同也刚好与第1个不同,此时前n-2个与前n个是一样的问题;
2)选定第一个的时候,第n-1个和第一个不同,此时最后一个只有一种选择,前n-1个和前n个是一样的问题。
所以:dp[i]=dp[i-1]+dp[i-2]*2

题目2:

晚会上(具体是不是晚会不太记得了…)所有人要站成一排。有三种颜色的衣服,要求相邻的人穿不同颜色的衣服。输入每种颜色衣服的数量,问总共有多少种排列方式。
例:
输入:1 1 1
输出:6

思路:

方法1:
递归,每次从和之前不同的颜色里找球,终止条件是:用完所有衣服或者无衣服可用。无衣服可用则表示不能这么排,返回0;
方法2:
dp,四维数组dp[i][j][p][l],i、j、p依次代表三种颜色球剩余数目,l代表前一个球的颜色。

题目3:

某人写了n封信和n个信封,如果所有的信都装错了信封。
求所有的信都装错信封共有多少种不同情况?

思路:

错拍问题,比较蠢得方法,全排列,然后找每一个排列是否每个位置都和索引不同,有相同的就扔掉就可以。
可以用递推的思想:
考虑第n个元素给它找一个位置,有n-1种,选择第k个,此时其余n-1个多的排列问题和刚才和n个是一样的问题,但是其实不能直接(n-1)*D(n-1),有两种方案;
i)第n个元素给它招一个位置,有n-1种,选择第k个,第k个和第一个对换,此时其他的是D(n-2),总的是(n-1)D(n-2);
2)第n个元素给它招一个位置,有n-1种,选择第k个,第k个和第一个没对换,放到其他位置,此时可以假设k本来就在第n个的位置,那么现在它要招一个其余的n-2个位置中的一个,相当于这n-1个元素的错排,就是D(n-1),所以总的是(n-1)D(n-1)
所以综上:d[i]=(n-1)(dp[i-1]+dp[i-2])

#include<bits/stdc++.h>
using namespace std;
//2.
void three_ball_count(vector<int>&ball,int last, int len,int &res){
    if(len==0)
        res++;
    for(int i=0;i<3;++i){
        if(i!=last&&ball[i]>0){
            ball[i]--;
            cout<<i<<" ";
             _count(ball,i, len-1, res);
            ball[i]++;
        }
    }
    cout<<endl;
}
int dp[50][50][50][4]={0};
int three_ball_count_dp(vector<int>&ball){
    int m=ball[0],n=ball[1],k=ball[2];

    dp[m][n][k][3]=1;
    for(int i=m;i>=0;--i){
        for(int j=n;j>=0;--j){
            for(int p=k;p>=0;--p){
                for(int l=0;l<=3;++l){
                    if(l==3){
                        if(i>0) dp[i-1][j][p][0]+= dp[i][j][p][l];
                        if(j>0) dp[i][j-1][p][1]+= dp[i][j][p][l];
                        if(p>0) dp[i][j][p-1][2]+= dp[i][j][p][l];
                    }
                    if(l==0){
                        if(j>0) dp[i][j-1][p][1]+= dp[i][j][p][l];
                        if(p>0) dp[i][j][p-1][2]+= dp[i][j][p][l];
                    }
                    if(l==1){
                        if(i>0) dp[i-1][j][p][0]+= dp[i][j][p][l];
                        if(p>0) dp[i][j][p-1][2]+= dp[i][j][p][l];
                    }
                    if(l==2){
                        if(i>0) dp[i-1][j][p][0]+= dp[i][j][p][l];
                        if(j>0) dp[i][j-1][p][1]+= dp[i][j][p][l];
                    }
                }
            }
        }
    }
    int res =0;
    for(int i=0;i<3;++i){
        res+=dp[0][0][0][i];
    }
    return res;
}
//3.
int cuopai(int n){
	vector<int>dp(n+1,0);
    dp[1]=0;
    dp[2]=1;
    for(int i=3;i<=n;++i){
    	dp[i]=(i-1)(dp[i-1]+dp[i-2]);
    }
    return dp[n];
}
int main(){

    //1.
    int n;
    cin>>n;
    vector<int>dp(n+1);
    dp[1]=3;
    dp[2]=6;
    dp[3]=6;
    for(int i=4;i<n;++i){
        dp[i]=dp[i-1]+2*dp[i-2];
    }
    cout<<dp[n];
    //2.
    vector<int>ball(3);
    int len=0;
    for(int i=0;i<3;++i){
        cin>>ball[i];
        len+=ball[i];
    }
    cout<<"len: "<<len<<endl;
    int last = -1;
    int res = 0three_ball_count(ball, last, len, res);
    int res2 = three_ball_count_dp(ball);
    cout<<res<<endl;
    cout<<res2;
    return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值