stl 题目总结

stl 题目总结

一、圆桌问题

 1 、问题:

圆桌上围坐着2n个人。其中n个人是好人,另外n个人是坏人。如果从第一个人开始数数,数到第m个人,则立即处死该人;然后从被处死的人之后开始数数,再将数到的第m个人处死……依此方法不断处死围坐在圆桌上的人。试问预先应如何安排这些好人与坏人的座位,能使得在处死n个人之后,圆桌上围坐的剩余的n个人全是好人。

输入:多组数据,每组数据输入:好人和坏人的人数n(<=32767)、步长m(<=32767);

输出:对于每一组数据,输出2n个大写字母,‘G’表示好人,‘B’表示坏人,50个字母为一行,不允许出现空白字符。相邻数据间留有一空行。

2、设计思路:

1)开辟一个动态数组,并初始化(编号1-2*n).

2)  根据步长、当前数组长度,求出应该“杀死”的人的下标,并按此下标将此人从数组中删去。

3)重复 2)直到数组中仅有 n 个人。

4)开辟一个标志数组,初始化全为 0 ,以动态数组的值作为下标,将对应位置的值改为 1。

5)输出序列,标志数组为 1 输出 ‘G’  为 0 输出 ‘B’。

代码:

#include<iostream>
#include<vector>
#include<cstring>
using namespace std;
int a[70000],n,m,cnt;
vector<int> v;
int main()
{
    while(cin>>n>>m)
    {
        v.clear();
        cnt=0;
        memset(a,0,sizeof(a));
        for(int i=1;i<=2*n;i++) v.push_back(i);
        while(v.size()>n)
        {
            cnt=(cnt+m-1)%v.size();///下标
            v.erase(v.begin()+cnt);///删除这个死人
         ///   cout<<cnt<<endl;
        }
        vector<int>::iterator it;
        for(it=v.begin();it!=v.end();it++){
            a[*it]=1;
         ///   cout<<*it<<endl;
        }

        for(int i=1;i<=2*n;i++)
        {
            if ((i-1)%50==0&&i>1) cout<<endl;
            if (a[i]) cout<<"G";
            else cout<<"B";
        }
        cout<<endl;
        cout<<endl;
    }
    return 0;
}

4、知识点总结。

1)未知组数据输入: while(cin>>n>>m)  Ctrl +  c,结束程序。

2)vector:在C++标准模板库中的部分内容它是一个多功能的能够操作多种数据结构和算法的模板类和函数库。作用它能够像容器一样存放各种类型的对象简单地说vector是一个能够存放任意类型的动态数组能够增加和压缩数据。使用vector需要注意以下几点

2-1)、如果你要表示的向量长度较长需要为向量内部保存很多数容易导致内存泄漏而且效率会很低

2-2)、Vector作为函数的参数或者返回值时需要注意它的写法double Distance(vector<int>&a, vector<int>&b) 其中的“&”绝对不能少

3)如果想要使用memset函数,需要在程序的开头添加string.h头文件。介绍memset函数是因为这个函数不是按照常规赋予一个初始值即可,memset函数使用的是按字节赋值,即对每个字节赋同样的值。

二、B - Text Reverse:(文本反转)

1、问题:Ignatius likes to write words in reverse way. Given a single line of text which is written by Ignatius, you should reverse all the words and then output them. (伊格纳修斯喜欢用相反的方式写单词。给出一行由伊格纳提斯写的文本,你应该把所有的单词倒过来,然后输出它们。)

输入:The input contains several test cases. The first line of the input is a single integer T which is the number of test cases. T test cases follow. Each test case contains a single line with several words. There will be at most 1000 characters in a line. (输入包含几个测试用例。输入的第一行是一个整数T,它是测试用例的数量。测试用例如下。每个测试用例包含一行,包含几个单词。一行最多有1000个字符。)

输出:For each test case, you should output the text which is processed. (对于每个测试用例,您应该输出所处理的文本。)

2-1、设计思路:

1)逐个字符读取单词,若字符不是空格或换行或结束标志,让字符进栈。

2)当字符不是空格或换行或结束标志时,输出栈内所有字母。

3)主意控制格式!!!

3、代码:

#include<stdio.h>
#include<stack>
using namespace std;
int main(){
    int n;
    char ch;
    scanf("%d",&n);
    getchar(); //!!!吸收回车符
    while(n--){
        stack<char> s; //定义栈
        while(true){
            ch=getchar(); //压栈时,一次压入一个字符
            if(ch==' '||ch=='
'||ch==EOF){
                while(!s.empty()){
                    printf("%c",s.top());
                    s.pop(); //清除栈顶元素
                }
                if(ch=='
'||ch==EOF)
                    break;  //绝对不能少,控制输出结束
                printf(" ");
            }
            else
                s.push(ch);
        }
        printf("
");
    }
    return 0;
}

4、知识点总结:

1)栈的典型特点:先进后出。

2)基本方法:empty() 堆栈为空则返回真;pop() 移除栈顶元素;push() 在栈顶增加元素;size() 返回栈中元素数目;top() 返回栈顶元素. . . . 

三、简单计算器 

1、题目:读入一个只包含 +, -, *, / 的非负整数计算表达式,计算该表达式的值。 

输入:测试输入包含若干测试用例,每个测试用例占一行,每行不超过200个字符,整数和运算符之间用一个空格分隔。没有非法表达式。当一行中只有0时输入结束,相应的结果不要输出。 

输出:对每个测试用例输出1行,即该表达式的值,精确到小数点后2位。 

2、设计思路:

1)读入第一个数字,和数字后的第一个字符若数字为 0 且字符为  ‘ ’ ,就结束程序。

2)否则,输入后一个字符,和数字,当字符是  ‘+’ 时,将此数存入数组,下标加一;当字符是  ‘-’ 时,将此数的相反数存入数组,下标加一;当字符是  ‘*’  时,将此数与数组最后一个数进行 * 运算,将结果还存到原位;当字符是  ‘/’ 时,将此数乘1.0与数组最后一个数进行 / 运算,将结果还存到原位;

3)读入下一个字符,若此字符是 ‘ ’ ,将数组中的数相加,按要求输出。否则,重复  2)。

 3、代码:

#include<iostream>
#include<stdio.h>
#include <cstring>
using namespace std ;
double s[205] ;
int main(){
    int f=0;
    char ch=' ';
    int n=0;
    char c;
    int top=0;
    while(cin>>f){
        ch=getchar();
        if(f==0&&ch=='
'){
            break;
        }
        memset( s , 0 , sizeof( s ) ) ;
        s[top]=f;
        while(cin>>c>>n  ){
            if( c == '+' ) s[++top] = n ;
            else if( c == '-' ) s[++top] = -n ;
            else if( c == '*' ) s[top] *= n ;    /// * 和 / 操作直接计算好,不算入下一个加减项
            else if( c == '/' ) s[top] /= n*1.0 ;
            cout<<(double)s[top]<<endl;
            if( getchar() == '
' )
                break ;
        }
        double rs=0.00;
        for(int i=0;i<=top;i++){
            rs+=(double)s[i];
        }
        printf("%.2f
",rs);
    }
    return 0;
}

4、知识点总结:

1)getchar();与cin>>ch;  & scanf("%c",&ch);的区别:

getchar();读入当前文件指针的下一个字符,cin>>ch;  & scanf("%c",&ch);默认以空格为分割符读入当前文件指针的下一个字符!

2)printf( "%.2lf " , rs ) ;输出浮点数时会按设置的位数进行四舍五入输出。

四、D - ACboy needs your help again!

1、问题:ACboy was kidnapped!! 

he miss his mother very much and is very scare now.You can't image how dark the room he was put into is, so poor :(. As a smart ACMer, you want to get ACboy out of the monster's labyrinth.But when you arrive at the gate of the maze, the monste say :" I have heard that you are very clever, but if can't solve my problems, you will die with ACboy." The problems of the monster is shown on the wall: Each problem's first line is a integer N(the number of commands), and a word "FIFO" or "FILO".(you are very happy because you know "FIFO" stands for "First In First Out", and "FILO" means "First In Last Out"). and the following N lines, each line is "IN M" or "OUT", (M represent a integer). and the answer of a problem is a passowrd of a door, so if you want to rescue ACboy, answer the problem carefully!(ACboy被绑架了!他非常想念他的母亲,现在很害怕,你无法想象他被安置在一个多么黑暗的房间里,那么可怜。作为一个聪明的ACMer,你想把ACboy从怪物的迷宫里救出来,但是当你到达迷宫的门口时,蒙斯特说:“我听说你很聪明,但是如果解决不了我的问题,你就会和ACboy一起死。”墙上显示了怪物的问题:每个问题的第一行都是整数N(命令数),还有一个单词“FIFO”或“filo”(你很高兴,因为你知道“FIFO”代表“先进先出”,“filo”表示“先到后出”)。下面的N行,每一行是“in M”或“out”,(m代表整数)。一个问题的答案是一个门的通行证,所以如果你想要拯救ACBOY,请仔细回答这个问题!)

输入:The input contains multiple test cases. The first line has one integer,represent the number oftest cases. And the input of each subproblem are described above.(输入包含多个测试用例。第一行有一个整数,表示测试用例的数量。并对每个子问题的输入进行了描述。)

输出:For each command "OUT", you should output a integer depend on the word is "FIFO" or "FILO", or a word "None" if you don't have any integer.(对于每个命令“out”,您应该输出一个依赖于单词   “FIFO  ”或    “filo” 的整数,如果没有任何整数,则输出一个单词“None”。)

 2、设计思路:

1)读入案例个数n,和进出形式str,本次案例个数m。

2)如果 str 是  “FIFO”  将数据放到队列中,否则将数据放到栈中。

3)读入字符串,若是 “OUT” 则输出栈顶或队头元素并将其移出,若栈或队列为空,则输出 “None”若是“IN”,读入数据并使其进栈或进队。

4)执行每次 3)后开始下一个案例

3、代码:

#include<stack>
#include<stdio.h>
#include<queue>
#include<cstring>
#include<iostream>
using namespace std ;

int main(){
    int n=0;
    int m=0;
    int t=0;
    string str;
    cin>>n;
    while(n--){
        cin>>m;
        cin>>str;
        cout<<str<<endl;
        if(str=="FIFO"){
            queue <int> q;
            while(m--){
                cin>>str;
                cout<<str<<endl;
                if(str=="IN"){
                    cin>>t;
                    q.push(t);
                }else{
                    if(q.empty()){
                        cout<<"None"<<endl;
                    }else{
                        cout<<q.front()<<endl;
                        q.pop();
                    }
                }
            }
        }else{
            stack <int> s;
            while(m--){
                cin>>str;
            if(str=="IN"){
                cin>>t;
                s.push(t);
            }else{
                if(s.empty()){
                    cout<<"None"<<endl;
                }else{
                    cout<<s.top()<<endl;
                    s.pop();
                }
            }
            }

        }
    }
}

 五、E - 看病要排队

1、问题:看病要排队这个是地球人都知道的常识。不过经过细心的0068的观察,他发现了医院里排队还是有讲究的。0068所去的医院有三个医生(汗,这么少)同时看病。而看病的人病情有轻重,所以不能根据简单的先来先服务的原则。所以医院对每种病情规定了10种不同的优先级。级别为10的优先权最高,级别为1的优先权最低。医生在看病时,则会在他的队伍里面选择一个优先权最高的人进行诊治。如果遇到两个优先权一样的病人的话,则选择最早来排队的病人。 现在就请你帮助医院模拟这个看病过程。

输入:输入数据包含多组测试,请处理到文件结束。每组数据第一行有一个正整数N(0<N<2000)表示发生事件的数目。 接下来有N行分别表示发生的事件。 一共有两种事件: 1:"IN A B",表示有一个拥有优先级B的病人要求医生A诊治。(0<A<=3,0<B<=10) 2:"OUT A",表示医生A进行了一次诊治,诊治完毕后,病人出院。(0<A<=3)

输出:对于每个"OUT A"事件,请在一行里面输出被诊治人的编号ID。如果该事件时无病人需要诊治,则输出"EMPTY"。 诊 治人的编号ID的定义为:在一组测试中,"IN A B"事件发生第K次时,进来的病人ID即为K。从1开始编号。 

2,设计思路、

1)自定义优先级队列,重写自定义数据类型“病人”的“<”运算符:若两个病人优先级相同,编号小的先看病,若优先级不同,优先级高的先看病。

2)创建一个优先级队列的数组。

3)读入第一个案例的操作数量n,读入事件若是"IN A B"事件则记录此病人的编号,和优先级B,并放入下标为A的优先级队列中。读入事件若是"OUT A"事件则让下标为A的优先级队列的队头元素出队,若队头为空则输出“EMOTY”。

4)重复执行 3)n此后开始下一个案例。

 3、代码

#include<iostream>
#include<cstdio>
#include<cstring>
#include<queue>
#include<stack>
using namespace std;

struct Node {
    int serial_number, priority;
    bool operator<(const Node &b) const {
        if (priority == b.priority){
            return serial_number > b.serial_number;
        }else{
            return priority < b.priority;
        }
    }
};

int main() {
    int n, d;
    char s[4];
    Node k;
    while (cin>>n){
        priority_queue<Node> q[4];
        int cot = 0;
        for (int i = 0; i < n; i++){
            scanf("%s", s);
            if (!strcmp(s, "IN")){///基本形式为strcmp(str1,str2),若str1=str2,则返回零;
                ++cot;
                cin>>d>>k.priority;
                k.serial_number = cot;
                q[d].push(k);
            }
            else{
                cin>>d;
                if (q[d].empty()){
                    cout<<"EMPTY"<<endl;
                }
                else{
                    cout<<q[d].top().serial_number<<endl;
                    q[d].pop();
                }

            }
        }
    }
    return 0;
}

4、知识点总结:

1)优先级队列本质上就是一个堆,在C++中有对应的实现std::priority_queue,该类主要提供以下接口:1.push 将一个元素放入队列中 2.top 返回队列中的一个元素 3.pop从队列中移除一个元素,

2)如果是自定义的类型的优先级队列,就要重载<运算符,或者自定义比较方法。

3)priority_queue 对于基本类型的使用方法相对简单。他的模板声明带有三个参数:priority_queue<Type, Container, Functional>其中Type 为数据类型, Container 为保存数据的容器,Functional 为元素比较方式。
Container 必须是用数组实现的容器,比如 vector, deque 但不能用 list.STL里面默认用的是 vector. 比较方式默认用 operator< , 所以如果你把后面俩个参数缺省的话,优先队列就是大顶堆,队头元素最大。

 六、F - 士兵队列训练问题

1、问题:某部队进行新兵队列训练,将新兵从一开始按顺序依次编号,并排成一行横队,训练的规则如下:从头开始一至二报数,凡报到二的出列,剩下的向小序号方向靠拢,再从头开始进行一至三报数,凡报到三的出列,剩下的向小序号方向靠拢,继续从头开始进行一至二报数。。。,以后从头开始轮流进行一至二报数、一至三报数直到剩下的人数不超过三人为止。 

输入:本题有多个测试数据组,第一行为组数N,接着为N行新兵人数,新兵人数不超过5000。 

输出:共有N行,分别对应输入的新兵人数,每行输出剩下的新兵最初的编号,编号之间有一个空格。 

2、设计思路:

1)读入案例个数和士兵总数。

2)为每个士兵从1编号存到队列中。

3)从1开始记录士兵报数的轮数,轮数为奇数1-2报数,为偶数1-3报数。

4)记录当前队列长度n,循环n次,以求余来模拟这些士兵报数出列的过程,若当前士兵编号对2或3求余结果不为0,则重新排队尾,等待下一轮报数。并将所有“报过数的士兵”删除。

5)重复执行 4)直到当前队列长度不超过3。

6)按要求输出队列中的所有元素,运算下一个案例。

3、代码:

#include<bits/stdc++.h>
using namespace std;
int main(){
    int N;cin>>N;
    while(N--){
        queue<int>q;
        int n;cin>>n;
        for(int i=1;i<=n;++i){ //编号
            q.push(i);
        }
        int cnt = 0;
        while(q.size()>3){
            cnt++;  //控制 2 、3 报数的标志
            int len = q.size();
            if(cnt%2==1){
                for(int i = 1;i<=len;++i){
                    if(i%2){
                        q.push(q.front()); //重新排队
                    }
                    q.pop(); //删除报过数的人
                }
            }else{
                for(int i = 1;i<=len;++i){
                    if(i%3){
                        q.push(q.front()); //重新排队
                    }
                    q.pop();//删除报过数的人
                }
            }
        }
        cout<<q.front();
        q.pop();
        while(!q.empty()){
            cout<<" "<<q.front();
            q.pop();
        }
        cout<<endl;
    }
    return 0;
}

七、G - 产生冠军

1、问题:有一群人,打乒乓球比赛,两两捉对撕杀,每两个人之间最多打一场比赛。 
球赛的规则如下: 
如果A打败了B,B又打败了C,而A与C之间没有进行过比赛,那么就认定,A一定能打败C。 
如果A打败了B,B又打败了C,而且,C又打败了A,那么A、B、C三者都不可能成为冠军。 
根据这个规则,无需循环较量,或许就能确定冠军。你的任务就是面对一群比赛选手,在经过了若干场撕杀之后,确定是否已经实际上产生了冠军。 

输入:输入含有一些选手群,每群选手都以一个整数n(n<1000)开头,后跟n对选手的比赛结果,比赛结果以一对选手名字(中间隔一空格)表示,前者战胜后者。如果n为0,则表示输入结束。 

输出:对于每个选手群,若你判断出产生了冠军,则在一行中输出“Yes”,否则在一行中输出“No”

2、设计思路

1)建立一个键为string类型值为整型的空map,模拟有向图度的概念,建立一个数组,下标对应选手的编号,值表示选手的入度。

2)读入选手的对数。

3)输入一对选手,在map找,他们是否在map中,若不在将他们编号,并放进map。

4)为失败者增加入度。

5)重复执行 3) 4) n次。

6)搜索记录入度的数组若只有一个入度为0的选手则有冠军输出“Yes”否则输出“NO”。

代码:

#include<iostream>
#include<cstring>
#include<cstdio>
#include<map>
/**
题解:这一题很水,说是用到拓扑排序,其实根本不用,
构建出一个图,只要记录所有点的入度,如果只有一个入度为0,
那么他就是冠军。不过构建图的时候有一个技巧,
如果单是用字符串去处理构建图,过程会有点繁琐,
如果用STL中map就简单很多了。
用map好处在于自带查找功能,
能够查找某个字符串是否在map中,
而且查找的复杂度是很低的。

*/
using namespace std;
int main(){
    int a[1000];
    int i,j=0,k=0;
    int f=0;
    string str1,str2;
    int n=0;
    while(cin>>n,n){
        memset(a,0,sizeof(a));
        map <string ,int> z;
        f=0;
        j=0;
        for(i=0;i<n;i++){
            cin>>str1>>str2;
            //若找不到,就将此人的姓名和编号存入字典
            if(z.find(str1)==z.end()){
                z[str1]=j;
                j++;
            }
            //若找不到,就将此人的姓名和编号存入字典
            if(z.find(str2)==z.end()){
                z[str2]=j;
                j++;
            }
           // cout<<j<<"  "<<a[z[str2]]+1<<endl;
           //模拟有向图,为失败者增加入度
            a[z[str2]]++;
        }
        for(i=0;i<j;i++){
            //cout<<a[i]<<endl;
            if(a[i]==0){
                f++;
            }
        }
        //若只有一个入度为0的节点则有冠军
        if(f==1){
            cout<<"Yes"<<endl;
        }else{
            cout<<"No"<<endl;
        }
    }
    return 0;
}

4、知识点总结:map-1

1)map是STL的一个关联容器,它提供一对一的hash。第一个可以称为关键字(key),每个关键字只能在map中出现一次;第二个可能称为该关键字的值(value);

2)map以模板(泛型)方式实现,可以存储任意类型的数据,包括使用者自定义的数据类型。Map主要用于资料一对一映射(one-to-one)的情況,map內部的实现自建一颗红黑树,这颗树具有对数据自动排序的功能。在map内部所有的数据都是有序的,后边我们会见识到有序的好处。比如一个班级中,每个学生的学号跟他的姓名就存在著一对一映射的关系。

3)自动建立key - value的对应。key 和 value可以是任意你需要的类型。

4)mop插入元素的三种方式:

// 定义一个map对象
map<intstring> mapStudent;
 
// 第一种 用insert函數插入pair
mapStudent.insert(pair<int, string>(000, "student_zero"));
 
// 第二种 用insert函数插入value_type数据
mapStudent.insert(map<int, string>::value_type(001, "student_one"));
 
// 第三种 用"array"方式插入
mapStudent[123] = "student_first";
mapStudent[456] = "student_second";

. . . . . 

八、H - Shopping

 1、问题:Every girl likes shopping,so does dandelion.Now she finds the shop is increasing the price every day because the Spring Festival is coming .She is fond of a shop which is called "memory". Now she wants to know the rank of this shop's price after the change of everyday.(每个女孩都喜欢购物,蒲公英也一样,现在她发现商店每天都在涨价,因为春节快到了,她喜欢一家叫做“记忆”的商店。现在她想知道每天变化后这家商店的价格等级。)

输入:One line contians a number n ( n<=10000),stands for the number of shops. 
Then n lines ,each line contains a string (the length is short than 31 and only contains lowercase letters and capital letters.)stands for the name of the shop. 
Then a line contians a number m (1<=m<=50),stands for the days . 
Then m parts , every parts contians n lines , each line contians a number s and a string p ,stands for this day ,the shop p 's price has increased s. 

(一行是n(n<=10000),代表商店的数量。然后n行,每一行包含一个字符串(长度小于31,只包含小写字母和大写字母。)代表商店的名称。然后,一个数m(1<=m<50)的直线代表日子。然后m个零件,每一个零件的n行,每一个线的一个数字s和一个字符串p,代表这一天,商店p的价格增加了s。)

输出:Contains m lines ,In the ith line print a number of the shop "memory" 's rank after the ith day. We define the rank as :If there are t shops' price is higher than the "memory" , than its rank is t+1.(包含m行,在第1行中打印出商店“内存”在第一天后的排名,定义为:如果有t家商店的价格高于“内存”,那么它的排名是t+1。)

2、设计思路:

1)建立一个键为string类型值为整型的空map,读入所有商家的名称,存入map先将其值设置为0。

2)读入天数和每天商店的价格,并以商店名为键,修改map中对应点值。

3)初始化"memory" 's的排名rank1为一,循环查找若map中值有比"memory" 's价格大的商店 rank1加一。

4)输出rank1。

3、代码

#include <iostream>
#include <map>
using namespace std;

int main(){
    int num,day;
    while(cin>>num){
        map<string ,int> pp;
        int ss;
        string kk;
        for(int i=0;i<num;i++){
           cin>>kk;
           pp[kk]=0;
        }
        cin>>day;
        while(day--){
            int rank1=1;
            for(int i=0;i<num;i++){
                cin>>ss>>kk;
                pp[kk]+=ss;
            }
            map<string ,int>::iterator iter;
            for (iter = pp.begin(); iter != pp.end(); iter++){
                if(iter->second>pp["memory"]){
                    rank1++;
                }
            }
            cout<<rank1<<endl;

        }
    }
    return 0;
}

4、知识点总结:map-2

1)当所查找的关键key出现时,它返回数据所在对象的位置,如果沒有,返回iter与end函数的值相同。

// find 返回迭代器指向当前查找元素的位置否则返回map::end()位置
iter = mapStudent.find("123");
 
if(iter != mapStudent.end())
       cout<<"Find, the value is"<<iter->second<<endl;
else
   cout<<"Do not Find"<<endl;

2)刪除与清空元素

//迭代器刪除
iter = mapStudent.find("123");
mapStudent.erase(iter);
 
//用关键字刪除
int n = mapStudent.erase("123"); //如果刪除了會返回1,否則返回0
 
//用迭代器范围刪除 : 把整个map清空
mapStudent.erase(mapStudent.begin(), mapStudent.end());
//等同于mapStudent.clear()

九、I - Ignatius and the Princess II

1、问题:

Now our hero finds the door to the BEelzebub feng5166. He opens the door and finds feng5166 is about to kill our pretty Princess. But now the BEelzebub has to beat our hero first. feng5166 says, "I have three question for you, if you can work them out, I will release the Princess, or you will be my dinner, too." Ignatius says confidently, "OK, at last, I will save the Princess." 

"Now I will show you the first problem." feng5166 says, "Given a sequence of number 1 to N, we define that 1,2,3...N-1,N is the smallest sequence among all the sequence which can be composed with number 1 to N(each number can be and should be use only once in this problem). So it's easy to see the second smallest sequence is 1,2,3...N,N-1. Now I will give you two numbers, N and M. You should tell me the Mth smallest sequence which is composed with number 1 to N. It's easy, isn't is? Hahahahaha......" 
Can you help Ignatius to solve this problem? (现在我们的英雄找到了通往Beelzebub feng5166的门。他打开门,发现风5166要杀了我们漂亮的公主。但现在贝塞布必须先打败我们的英雄。冯5166说:“我有三个问题要问你,如果你能解决,我会释放公主,否则你也会成为我的晚餐。”伊格纳修斯自信地说:“好吧,我终于要救公主了。”“现在我将向你们展示第一个问题。”Feng5166说:“给定一个从1到N的序列,我们定义了1,2,3.N-1,N是所有可以由1到N组成的序列中最小的序列(每个数可以并且应该在这个问题中只使用一次)。所以很容易看到第二个最小的序列是1,2,3.N,N-1。现在我给你两个数字,N和M,你应该告诉我第m个最小的序列,它是由数字1到N组成的,这很简单,不是吗?哈哈哈哈.“你能帮伊格纳修斯解决这个问题吗?)

输入:The input contains several test cases. Each test case consists of two numbers, N and M(1<=N<=1000, 1<=M<=10000). You may assume that there is always a sequence satisfied the BEelzebub's demand. The input is terminated by the end of file. (输入包含几个测试用例。每个测试用例由两个数字组成,N和M(1<=N<=1000,1<=M<=10000)。您可能会假设总是有一个序列满足Beelzebub的要求。输入将在文件结束时终止。)

输出:For each test case, you only have to output the sequence satisfied the BEelzebub's demand. When output a sequence, you should print a space between two numbers, but do not output any spaces after the last number. (对于每个测试用例,只需输出满足Beelzebub要求的序列即可。在输出序列时,应在两个数字之间打印空格,但不要在最后一个数字之后输出任何空格。)

2、设计思路:

1)读入 n ,m,创建数组初始化存入 1-n

2)将数组用next_permutation()重新排序 m-1次

3)   输出数组。

3、代码

#include<stdio.h>
#include<algorithm>
#include<cmath>
#include<iostream>
using namespace std;
int main(){
    int a[1010];
    int n,m;
    while(cin>>n>>m) {
        for(int i=0;i<n;i++){
            a[i]=i+1;//初始化
        }
        for(int i=1;i<m;i++){
            //每执行一次,就重新排序一次
            next_permutation(a,a+n);
            //执行m-1次后输出结果
            if(i==m-1){
                for(int j=0;j<n-1;j++){
                    cout<<a[j];
                }
                cout<<a[n-1]<<endl;
            }
        }
    }
    return 0;
}

4、知识点总结:

1)组合数学中经常用到排列,这里介绍一个计算序列全排列的函数:next_permutation(start,end),和prev_permutation(start,end)。这两个函数作用是一样的,区别就在于前者求的是当前排列的下一个排列,后一个求的是当前排列的上一个排列。

2)此外,next_permutation(node,node+n,cmp)可以对结构体num按照自定义的排序方式cmp进行排序。

也可以对字符...

十、J - 排列2

1问题:Ray又对数字的列产生了兴趣:现有四张卡片,用这四张卡片能排列出很多不同的4位数,要求按从小到大的顺序输出这些4位数。 

输入:每组数据占一行,代表四张卡片上的数字(0<=数字<=9),如果四张卡片都是0,则输入结束。 

输出:对每组卡片按从小到大的顺序输出所有能由这四张卡片组成的4位数,千位数字相同的在同一行,同一行中每个四位数间用空格分隔。 每组输出数据间空一行,最后一组数据后面没有空行。 

2、设计思路:

1)读入四个数字,并判断若四个数字全为0,则结束。

2)将输入的四个数字排序。

3)若排序后的第一个数是0,用next_permutation()得到下一个排列,若得不到则结束。

4)用标记记录当前的千位数字,进入循环,用next_permutation()得到下一个排列,若得不到则结束,否则继续,当标记与当前的千位数字不同时,跳出循环输出换行。

5)重复 4)直到结束。

 3、代码

#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include<algorithm>
using namespace std;
int main(){
    int a[5];
    int count=1;
    while(scanf("%d%d%d%d",&a[0],&a[1],&a[2],&a[3])!=EOF){
        if(a[0]==0&&a[1]==0&&a[2]==0&&a[3]==0)
            break;
        if(count!=1)
            printf("
");
        sort(a,a+4);
        while(1){
            if(a[0]==0){
                //如果存在a之后的排列,就返回true。如果a是最后一个排列没有后继,返回false,每执行一次,a就变成它的后继
                if(next_permutation(a,a+4))
                    continue;
                else
                    break;
            }
            int temp=a[0];
            bool jud=false;
            int cnt=1;
            while(a[0]==temp){//保持千位相同的在一行
                int i;
                if(cnt!=1){
                     printf(" ");
                }
                for(i=0;i<4;i++){
                    printf("%d",a[i]);
                }
                cnt++;
                if(!next_permutation(a,a+4)){
                    jud=true;
                    break;
                }
            }
            printf("
");
            if(jud)
                break;
        }
        count++;
    }
    return 0;
}
原文地址:https://www.cnblogs.com/20183544-wangzhengshuai/p/11944055.html