NOIP 灯的排列问题

题目描述

设在一排上有N个格子(N≤20),若在格子中放置有不同颜色的灯,每种灯的个数记为N1,N2,……Nk(k表示不同颜色灯的个数)。

   放灯时要遵守下列规则:

①同一种颜色的灯不能分开;

②不同颜色的灯之间至少要有一个空位置。

   例如:N=8(格子数)

         R=2(红灯数)

         B=3(蓝灯数)

   放置的方法有:

      R-B顺序

R

R

 

B

B

B

 

 

R

R

 

 

B

B

B

 

R

R

 

 

 

B

B

B

 

R

R

 

B

B

B

 

 

R

R

 

 

B

B

B

 

 

R

R

 

B

B

B

   

      B-R顺序

B

B

B

 

R

R

 

 

B

B

B

 

 

R

R

 

B

B

B

 

 

 

R

R

 

B

B

B

 

R

R

 

 

B

B

B

 

 

R

R

 

 

B

B

B

 

R

R

    放置的总数为12种。

    程序要求:求排列总数。

输入格式

数据输入的方式为:

N

P1(颜色,为一个字母) N1(灯的数量)

P2 N2

……

Q(结束标记,Q本身不是灯的颜色)

 颜色和灯的数量之间由一个空格分隔。

输出

输出排列总数。

样例输入

8
R 2
B 3
Q

样例输出

12


注意同意颜色归到一起

暴力搜索出一种颜色顺序下的所有顺序

再将它乘上N种颜色的排列数N!

即可得到总排列数。。。。


代码:

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
using namespace std;
struct color{    //没必要用结构体  开始想复杂了 数组就OK
   char aa;
   int bb;
}q[10];
int num=0,s;
int sss=0;      //同意颜色顺序下排序数
void dfs(int a,int b,int c)          //a表示已用颜色  b表示已放格子数  c表示是否要放空格
{
    if(a==num&&b==s)
        {
            sss++;
            return;
        }
    if(b>s)
        return;
        if(c!=1)
    dfs(a+1,b+q[a].bb,1);
    dfs(a,b+1,0);
}
int main()
{
    int i,j;
    int sum;
    int ss=0;
    char a;
    int b;
    scanf("%d",&s);
    while(cin>>a&&a!='Q')
    {
        scanf("%d",&b);
        ss=ss+b;
        int t=0;
        for(i=0;i<num;i++)
          {
              if(q[i].aa==a)
                {
                    q[i].bb+=b;
                    t=1;
                }
          }
          if(t==0)
          {
              q[num].aa=a;
              q[num++].bb=b;
          }
    }
    int per=1;
    for(i=1;i<=num;i++)
        per=per*i;
    if(s-ss-num+1<=0)         //格子不够
        cout<<0<<endl;
    else
    {
        dfs(0,0,0);
        cout<<sss*per<<endl;
    }
    return 0;
}


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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值