寒假happy1-全排列与PREV-3 带分数

        从n个不同元素中任取m(m≤n)个元素,按照一定的顺序排列起来,叫做从n个不同元素中取出m个元素的一个排列。当m=n时所有的排列情况叫全排列。如果这组数有n个,那么全排列数为n!个。
        Ex:a,b,c的全排列一共有3!= 6 种 分别是{a, b, c}、{a, c, b}、{b, a, c}、{b, c, a}、{c, a, b}、{c, b, a}。


1.非stl的全排列

先来个代码:以1-9数字的全排列为例:

void permutation(int st,int n){
    if(st == n) DO(pmut);//DO为对排列结果的操作
    else{
        for(int i = 1;i <= 9;i++){//1-9全排列
            if(!vis[i]){
                pmut[st] = i;
                vis[i] = 1;
                permutation(st + 1,n);
                vis[i] = 0;
            }
        }
    }
}

·pmut记录每一个排列:对于全排列中st,表示排列的结果是从st开始记录一直记录到n,一般取st = 1,vis记录所排列的数据是否被访问过了,则全排列其实就是一个枚举,对pmut数组的每个位置依次放入数据,例如st位置依次放置从1-9的数字,然后知道数组放满(到n位置)结束,则此时pmut就是一种排列。

·DO函数表示对每一个排列的结果的操作,例如输出排列的结果:

#include<bits/stdc++.h>

using namespace std;
const int maxn = 106;
int pmut[maxn];
int vis[maxn];

void DO(int pmut[]){
    for(int i = 1;i <= 9;i++)
        cout<<" "<<pmut[i];
    cout<<endl;
}


void permutation(int st,int n){
    if(st == n) DO(pmut);
    else{
        for(int i = 1;i <= 9;i++){
            if(!vis[i]){
                pmut[st] = i;
                vis[i] = 1;
                permutation(st + 1,n);
                vis[i] = 0;
            }
        }
    }
}

int main(){
    memset(vis,0,sizeof vis);
    permutation(1,10);
    return 0;
}

2.stl-next_permutation与prev_permutation(bool)函数

1.头文件

#include <algorithm>

2.下一个排列与上一个排列的概念:

我们假设一个数组为1 2 7 5,对此进行升序排列:1 2 5 7,此时定义此数组的升序排列为所有排列的第一个排列结果,则此下一个排序结果为1 2 7 5,1 5 2 7...

也就是说是:对序列 {a, b, c},每一个元素都比后面的小,按照字典序列,固定a之后,a比bc都小,c比b大,它的下一个序列即为{a, c, b},而{a, c, b}的上一个序列即为{a, b, c},同理可以推出所有的六个序列为:{a, b, c}、{a, c, b}、{b, a, c}、{b, c, a}、{c, a, b}、{c, b, a},其中{a, b, c}没有上一个元素,{c, b, a}没有下一个元素。

1)next_permutation:求下一个排列组合 

a.函数模板:next_permutation(arr, arr+size);
b.参数说明:
  arr: 数组名
  size:数组元素个数
c.函数功能: 返回值为bool类型,当当前序列不存在下一个排列时,函数返回false,否则返回true,排列好的数在数组中存储

d.注意:在使用前需要对欲排列数组按升序排序,否则只能找出该序列之后的全排列数。
    比如,如果数组num初始化为2,3,1,那么输出就变为了:{2 3 1} {3 1 2} {3 2 1}

2)prev_permutation:求上一个排列组合

a.函数模板:prev_permutation(arr, arr+size);
b.参数说明:
  arr: 数组名
  size:数组元素个数
c.函数功能: 返回值为bool类型,当当前序列不存在上一个排列时,函数返回false,否则返回true
d.注意:在使用前需要对欲排列数组按降序排序,否则只能找出该序列之后的全排列数。

对上面那个代码用stl书写一遍(1-9数字的全排列):

#include<bits/stdc++.h>

using namespace std;
const int maxn = 106;
int pmut[maxn];

void DO(int pmut[]){
    for(int i = 1;i <= 9;i++)
        cout<<" "<<pmut[i];
    cout<<endl;
}


int main(){
    for(int i = 1;i <= 9;i++)
        pmut[i] = i;
    do{
        DO(pmut);
    }while(next_permutation(pmut + 1,pmut + 10));
    return 0;
}

3.PREV-3 带分数

问题描述

100 可以表示为带分数的形式:100 = 3 + 69258 / 714。

还可以表示为:100 = 82 + 3546 / 197。

注意特征:带分数中,数字1~9分别出现且只出现一次(不包含0)。

类似这样的带分数,100 有 11 种表示法。

输入格式

从标准输入读入一个正整数N (N<1000*1000)

输出格式

程序输出该数字用数码1~9不重复不遗漏地组成带分数表示的全部种数。

注意:不要求输出每个表示,只统计有多少表示法!

样例输入1

100

样例输出1

11

样例输入2

105

样例输出2

6

分析:

将这个题看成这样的形式num = a + b / c,也就是说a,b,c三个数字是1-9数字的一种情况,然后再在其中加入一个+号和一个/号,也就是我们只需要知道所有的排列结果,然后在其中合适的位置插入+和/号即可,为了简化枚举的情况,分析a,b,c的情况:(a)表示a的位数

1.a <= num

2.(c)min = 1

3.a是整数,所有b/c也是整数,即b % c = 0

4.b > c  ->   (b) >= c,由此可以推出了( 9 - (a) ) / 2 <= (b) <= 8 - (a)

对于全排列的每一个结果pmut,枚举插入+的位置(i),则之前就是a,后面的部分枚举/的位置(j),则i + 1到j的为b,剩下的为c即可

由此就可以直接解出此题(stl与非stl):

1.不使用stl

#include<iostream>
#include<cstring>
using namespace std;
int vis[10];
int pmut[10];
int sum;
int num;

void DO(int pmut[]) {
    int a,b,c;//i,j,rest
    for(int i = 1;i <= 9;i++) {
        a = 0;
        for(int k = 1;k <= i;k++){
            a = a*10 + pmut[k];
            if(a >= num) return ;
        }
        for(int j = (9 - i)/2 + i;j <= 8;j++) {
            b = 0,c = 0;
            for(int k = i + 1;k <= j;k++)
                b = b*10 + pmut[k];
            for(int k = j + 1;k <= 9;k++)
                c = c*10 + pmut[k];
            if(b % c == 0 && a + b/c == num)
                sum++;
        }
    }
}

void permutation(int st,int n) {
    if(st == n) DO(pmut);
    else {
        for(int i = 1;i <= 9;i++) {
            if(!vis[i]) {
                pmut[st] = i;
                vis[i] = 1;
                permutation(st + 1,n);
                vis[i] = 0;
            }
        }
    }
}

int main() {
    while(cin>>num){
        memset(vis,0,sizeof(vis));
        sum = 0;
        permutation(1,10);
        cout<<sum<<endl;
    }
    return 0;
}

2.stl

#include<bits/stdc++.h>

using namespace std;
const int maxn = 16;

int pmut[maxn];
int sum;
int num;

void DO(int pmut[]) {
    int a,b,c;//i,j,rest
    for(int i = 1;i <= 9;i++) {
        a = 0;
        for(int k = 1;k <= i;k++){
            a = a*10 + pmut[k];
            if(a >= num) return ;
        }
        for(int j = (9 - i)/2 + i;j <= 8;j++) {
            b = 0,c = 0;
            for(int k = i + 1;k <= j;k++)
                b = b*10 + pmut[k];
            for(int k = j + 1;k <= 9;k++)
                c = c*10 + pmut[k];
            if(b % c == 0 && a + b/c == num)
                sum++;
        }
    }
}

int main(){
    for(int i = 1;i <= 9;i++)
        pmut[i] = i;
    while(cin>>num){
        sum = 0;
        do{
            DO(pmut);
        }while(next_permutation(pmut + 1,pmut + 10));
        cout<<sum<<endl;
    }

    return 0;
}

猜你喜欢

转载自blog.csdn.net/guifei0/article/details/86621590