zoukankan      html  css  js  c++  java
  • 使用C++生成排列数(打印隔板法问题的所有解)

    问题和思路来源于:https://www.zhihu.com/question/51448931

    1. 问题描述

    有n个相同的球,m个盒子(编号为1,2,……m),将这n个球放入这m个盒子中,要求输出所有可能的放置方法。

    2. 问题思路

    那这个正常情况下是用递归进行计算的,递归的话可能要在程序运行时开很大的内存(数据大的话)。
    看到回答里有个老哥用位运算,没有调递归,我就试着写了一下状压版本的。
    按照插板法进行模拟,一个m+n-1个位置,如果位置上是1的话,那么就是放板子的位置。如果是0的话,那么就是球的位置。这样把问题化成了一个指定总长度,指定1的个数的一个二进制数有哪些的问题了。二进制数有大小可以做参考,进行枚举的话不会漏掉的。
    在枚举的过程中,将数字按从小到大进行排序枚举,每次在选择1的位置的时候采取贪心策略,也就是让尽量多的零在高位上。
    当然,这次的代码也没评测姬,所以有bug的话,我会尽量的修复。

    #include <iostream>
    #include <bitset>
    #include <algorithm>
    #include <string>
    using namespace std;
    const int size = 1000;
    bitset<size> tot;
    int pos_h, pos_t;
    int m=3, b=20;
    int f[100][100];
    void init() {
        for(int i = 0; i <= 99; i++) {
            f[i][i] = f[i][0]=1;
        }
        for(int i = 1; i <= 99; i++)
            for(int j = 1; j < i; j++)
                f[i][j] = f[i-1][j] + f[i-1][j-1];
    }
    void change(int bar) {
        int last = 0;
        int mid = 0;
        bool flag_mid= false;
        bool flag_begin = false;
        int cnt = 0;
        // cout << bar << " " << pos_h << endl;
        for (int i = 0; i < pos_h; i++) {
            if (tot[i]) flag_begin = true;
            if (tot[i] == 0) cnt++;
            if (tot[i] == 0 and flag_begin) {
                for (int j = 1; j <= cnt; j++) tot[i-j] = 0;
                for (int j = cnt+1; i-j >= 0; j++) tot[i-j] = 1;
                tot[i] = 1;
                return;
            }
        }
        tot.reset();
        for (int i = 0; i < bar-1; i++) tot.set(i);
        tot.set(pos_h);
        pos_h++;
    }
    
    
    int main() 
    {
        init();
        ios::sync_with_stdio(false);
        cout << "input m b:";
        cin >> m >> b;
        freopen("out.txt", "w" ,stdout);	
        int bar = m - 1;
        pos_h = bar;
        int cnt = 0;
        for (int i = 0; i < bar; i++) tot.set(i);
        while (true) {
            // cout << tot << endl;
            string tmp = tot.to_string();
            reverse(tmp.begin(), tmp.end());
            // cout << tmp << endl;
            int last_pos = 0;
            for (int j = 0; j < m+b-1; j++) {
                if(tmp[j] == '1') {
                    if (last_pos == 0 and tmp[0] == '0') last_pos--;
                    cout << max(0, j - last_pos - 1) << " ";
                    last_pos = j;
                }
            }
            cout << m+b-last_pos-2 << endl;
            cnt++;
            change(bar);
            if (tot[m+b-1]) break;
        }
        int ans = f[m+b-1][m-1];
        cout << "cal with comb is: " << ans <<endl;
        cout << "list length is: " << cnt << endl;
        return 0;
    }
    
  • 相关阅读:
    选择本地照片之后即显示在Img中(客户体验)
    解决JQuery.ajax.post乱码问题
    浅析MVC模式与三层架构的区别01
    照片上传(缩略图实现)
    基于Netty的聊天系统(三)协议定制----消息篇
    基于Netty的聊天系统(二)协议定制----登录篇
    基于Netty的聊天系统(一)通讯原理篇
    Centos6.5下配置SVN服务器
    FreeMarker-TemplateLoader
    移动UI自动化-Page Objects Pattern
  • 原文地址:https://www.cnblogs.com/cniwoq/p/13170849.html
Copyright © 2011-2022 走看看