noip 1995 灯的排列问题 排列组合 DFS

题目描述

设在一排上有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

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<vector>
using namespace std;
struct color{
   char aa;
   int bb;
}q[10];
struct node
{
    char x;
    int y;
}miss[30];
int num=0,s;
int sss=0;
vector<int> qq[1000];
vector<int> m;
int kiss=0;
void dfs(int a,int b,int c)
{
    if(a==num&&b==s)
    {
        sss++;
        //cout<<m.size()<<endl;
        for(int i=0;i<m.size();i++)
        {
            qq[kiss].push_back(m[i]);
        }
        kiss++;
        for(int i=0;i<m.size();i++)
        {
            cout<<qq[kiss-1][i];
        }
        cout<<endl;
        return;
    }
    if(b>s)
        return;
    if(c!=1)
    {
        m.push_back(1);
        dfs(a+1,b+q[a].bb,1);
        m.pop_back();
    }
    m.push_back(0);
    dfs(a,b+1,0);
    m.pop_back();

}
int main()
{
    kiss=0;
    int i,j;
    int sum;
    int ss=0;
    char a;
    int b;
    scanf("%d",&s);
    int pp=0;
    while(cin>>a&&a!=‘Q‘)
    {
        miss[pp].x=a;
        scanf("%d",&b);
        miss[pp++].y=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<<"1"<<endl;
        for(int i=0;i<pp;i++)
            cout<<miss[i].x<<" "<<miss[i].y<<endl;
        */
        int a[10];
        for(int ii=0;ii<kiss;ii++)
        {
            for(int i=0;i<pp;i++)
                a[i]=i;
            int flag=0;
            for(int i=0;i<qq[ii].size();i++)
            {
                //cout<<"1";
                if(qq[ii][i]==0)
                    cout<<" ";
                else
                {
                    for(int j=0;j<miss[a[flag]].y;j++)
                        cout<<miss[a[flag]].x;
                    flag++;
                }
            }
            cout<<endl;

            while(next_permutation(a,a+pp))
            {
                flag=0;
                for(int i=0;i<qq[ii].size();i++)
                {
                    if(qq[ii][i]==0)
                        cout<<" ";
                    else
                    {
                        for(int j=0;j<miss[a[flag]].y;j++)
                            cout<<miss[a[flag]].x;
                        flag++;
                    }
                }
                cout<<endl;
            }
        }
        cout<<sss*per<<endl;
    }
    return 0;
}
时间: 2024-08-10 21:28:49

noip 1995 灯的排列问题 排列组合 DFS的相关文章

一道笔试题-给定一个正整数序列,请尝试将它们重新排列使得排列的结果最大。

问题描述:给定一个正整数序列,请尝试将它们重新排列使得排列的结果最大,例如正整数序列为9,31,35,3,7则最大值为9735331. 思路分析:先将正整数序列转换为字符串数组,然后字符串数组进行排序,最后依次输出字符串数组即可.根据题目的要求,两个数字m和n排成的数字mn和nm,如果mn<nm,那么我们应该输出nm,也就是m应该排在n的后面,也就是m<n.反之,如果nm<mn,m排在n的前面,n<m.如果mn==mn,m等于n. 比较函数的定义是本解决方案的关键.这道题其实就是希

nyoj19擅长排列的小明(DFS或STL)

擅长排列的小明 时间限制:1000 ms  |  内存限制:65535 KB 难度:4 描述 小明十分聪明,而且十分擅长排列计算.比如给小明一个数字5,他能立刻给出1-5按字典序的全排列,如果你想为难他,在这5个数字中选出几个数字让他继续全排列,那么你就错了,他同样的很擅长.现在需要你写一个程序来验证擅长排列的小明到底对不对. 输入 第一行输入整数N(1<N<10)表示多少组测试数据, 每组测试数据第一行两个整数 n m (1<n<9,0<m<=n) 输出 在1-n中选

C语言 &#183; 排列数 &#183; 排列式

蓝桥练习场上不断碰到类似的题,都是一个递归搜索的套路. 算法提高 排列数 时间限制:1.0s   内存限制:256.0MB 问题描述 0.1.2三个数字的全排列有六种,按照字母序排列如下: 012.021.102.120.201.210 输入一个数n 求0~9十个数的全排列中的第n个(第1个为0123456789). 输入格式 一行,包含一个整数n 输出格式 一行,包含一组10个数字的全排列 样例输入 1 样例输出 0123456789 数据规模和约定 0 < n <= 10! 作者注释:标准

noip复习之数学(4)——组合游戏

我们在此专题中将考虑这样一类组合游戏: (1)两个游戏者轮流操作 (2)游戏的状态集有限,并且不管双方怎么走,都不会再出现以前的状态.这保证了游戏在有限步内结束. (3)谁不能操作谁输,这样的规则避免了平局的出现. 而且我们只考虑公平游戏,即如果一个游戏者可以把状态A变为B,另一个游戏者也可以.国际象棋并不是公平游戏,因为白方可以移动白子,而黑方却不能移动白子. 状态图:为方便描述,我们可以把游戏中的状态画成图.每个节点是一个状态,每条边代表从一个状态转移到另一个状态的操作. 注意:先手必胜状态

排列组合知识

1.在不全相异的n个物体中,其中有n1个物体是相同的,n2个物体是相同的,……nk个物体是相同的.全部物体的种类数为k,则这n个物体的全排列数为 n!/(n1!*n2!*……*nk!) 2.用n-1条边将n个顶点连接的图有n^(n-2)个. 3.圆周排列 从N个元素中取出R个元素形成圆周排列,排列数为A(N,R)/R; 同理,N个元素的圆周排列数为(N-1)!; 4.按字典序生成下一个排列组合 ①从后往前找第一个正序的尾下标i,pi>p(i-1),pi>p(i+1): ②找p(i-1)后面其大

字符串的排列组合

1.字符串的组合 字符串的组合,有字符串abc,它的所有组合为a,b,c,ab,ac,abc.求字符串的组合可以使用递归的方法,程序如下: void print(string &s,int start,vector<char> &t) { if(start==s.size()) { return ; } int i=0; for(i=start;i<s.size();++i) { t.push_back(s[i]); //使用递归+回溯的方法求组合 vector<c

【程序员眼中的统计学(5)】排列组合:排序、排位、排

排列组合:排序.排位.排 作者 白宁超 2015年10月15日18:30:07 摘要:程序员眼中的统计学系列是作者和团队共同学习笔记的整理.首先提到统计学,很多人认为是经济学或者数学的专利,与计算机并没有交集.诚然在传统学科中,其在以上学科发挥作用很大.然而随着科学技术的发展和机器智能的普及,统计学在机器智能中的作用越来越重要.本系列统计学的学习基于<深入浅出统计学>一书(偏向代码实现,需要读者有一定基础,可以参见后面PPT学习).正如(吴军)先生在<数学之美>一书中阐述的,基于统

【原创】开源.NET排列组合组件KwCombinatorics使用(二)——排列生成

你还可以参考本博客其他.NET开源项目的相关文章: [原创]彩票预测算法:离散型马尔可夫链模型          Newlife XCode组件资源目录汇总[2013年版] [原创]开源.NET下的XML数据库介绍及入门          [原创].NET开源压缩组件介绍与入门 [开源].NET开源表达式计算组件介绍与使用          [原创]开源Word读写组件DocX介绍与入门 [原创]Matlab.NET混编调用Figure窗体                [原创]Matlab与.

经典算法学习之分治法(以排列、组合程序为例)

分治法的思想:将原问题分解为几个规模较小但类似于原问题的子问题,递归的求解这些子问题,然后再合并这些子问题的解来建立原问题的解. 分治法在每层递归是遵循的三个步骤: (1)分解原问题为若干个子问题,这些子问题是原问题的规模较小的实例. (2)解决这些子问题,队规的求解各个子问题,当子问题规模足够小的时候,直接求解. (3)合并这些子问题的解构成原问题的解. 显然归并排序是一个非常经典规矩的分治法的例子,鉴于之前已经写过一篇关于归并排序的博文,这里不在使用归并排序作为例子. 注意分治法的每一层递归