状态枚举类Enumerator源代码,欢迎拍砖!

竞天问 2013-01-25 11:08:04
初衷是解决智力题中的较复杂的推理题,比如:
有5个人参加某项比赛,但是参赛人员必须满足:
1、如果A参加,则B一定参加
2、C和D有且只有一人参加
3、D和E要么都参加,要么都不参加
4、如果C参加,则B一定不参加
5、最多有两个人参加
问满足条件的参赛人选。
我知道Prolog擅于解决此类问题,但是我擅用的语言是C++,所以就有了下面的代码。至于实用于否就不管了,权当是做了一个codekata,欢迎大家拍砖!
我的空间里也有
我用的是VS2012,我必须要undef max才能使用std::limits<>::max()函数,很上火!

#pragma once

#include<limits>
#include<vector>
#include<string>
#include<boost/lexical_cast.hpp>
#undef max
template<unsigned int BASE, class TYPE=unsigned>
class Enumerator
{
static_assert(BASE > 2, "template parameter should greater than 2!");
public:
// typedef unsigned int TYPE;

Enumerator(unsigned int count, TYPE stat = 0)
{
status.clear();
status.resize(count, stat);
}
bool operator ++()
{
int c = 1;

for (size_t i = 0 ; c != 0 && i < status.size() ; ++i)
{
status[i] += c;
if(status[i] >= BASE)
{
status[i] = 0;
c = 1;
}
else
{//不需要再继续进位
c = 0;
}
}
return c == 0;
}
bool operator++(int)
{
return this->operator++();
}
TYPE get(size_t i) const
{
if(i >= status.size())
throw std::out_of_range(std::string("i should less than ")
+ lexical_cast<string>(status.size()));
return status[i];
}
void set(size_t i, TYPE s)
{
if(i >= status.size())
throw std::out_of_range(string("i should less than ")
+ lexical_cast<string>(status.size()));
status[i] = s;
}
size_t count(TYPE s) const
{
size_t result = 0;
for (const auto& p : status)
{
if(p == s) result++;
}
return result;
}
size_t size() const
{
return status.size();
}
protected:
private:
std::vector<TYPE> status;
};
template<class T>
class Enumerator<2, T>
{
//只要是这种2状态的东西,直接采用unsigned类型,忽略类型参数T
typedef unsigned int TYPE;
public:
Enumerator(unsigned int count, bool statu = 0)
:SIZE(count)
{
status.clear();
status.resize(SIZE / BITS + 1, statu ? std::numeric_limits<TYPE>::max() : 0);
}
bool operator++()
{
static const auto MAX = std::numeric_limits<TYPE>::max();
int c = 1;

for (size_t i = 0 ; c != 0 && i < status.size() ; ++i)
{
if(status[i] == MAX)
{
status[i] = 0;
c = 1;
}
else
{
status[i]+=c;
c = 0;
}
}
return c == 0 && (status.back() >> (SIZE % BITS)) == 0;
}
bool operator++(int)
{
return operator++();
}
short get(size_t i) const
{
if(i >= SIZE) throw std::out_of_range(std::string("i should less than ") + boost::lexical_cast<std::string>(SIZE));
return (status[i / BITS] >> (i % BITS)) & 1;
}
void set(size_t i , bool s)
{
if(s)
status[i / BITS] |= 1 << (i % BITS);
else
status[i / BITS] &= ~(1 <<( i % BITS));
}
size_t count(bool s) const
{
unsigned result = 0;
for (auto p : status)
{
while(p)
{
result += p & 1;
p >>= 1;
}
}

return s ? result : SIZE - result;
}
size_t size() const
{
return SIZE;
}
protected:
private:
static const auto BITS = std::numeric_limits<TYPE>::digits;
const size_t SIZE;
std::vector<TYPE> status;
};


然后可以用如下代码来解上面的问题:


#include "Enumerator.h"
#include <iostream>
using std::cout;
using std::endl;
bool Check(const Enumerator<2>& e)
{
assert(e.size() == 5);
const int A = 0;
const int B = 1;
const int C = 2;
const int D = 3;
const int E = 4;
//如果A参加,则B一定参加
if(e.get(A) && !e.get(B))
return false;
//C和D有且只有一人参加
if(e.get(C) == e.get(D)) return false;
//D和E状态一致
if(!(e.get(D) == e.get(E))) return false;
//如果C参加,则B不参加
if(e.get(C) && e.get(B)) return false;
//最多有两个人参加
if(e.count(true) > 2) return false;

return true;

}
int _tmain(int argc, _TCHAR* argv[])
{
Enumerator<2> d(5,0);

do
{
if(Check(d))
{
for (int i = 0 ; i <d.size() ; ++i)
{
cout<<(short)d.get(i);
}

cout<<endl;
}
} while (d++);

system("pause");
return 0;
}



...全文
251 17 打赏 收藏 转发到动态 举报
写回复
用AI写文章
17 条回复
切换为时间正序
请发表友善的回复…
发表回复
竞天问 2013-01-31
  • 打赏
  • 举报
回复
引用 13 楼 zhaokai115 的回复:
C/C++ code?1#define NO_MINMAX

#ifndef NOMINMAX

#ifndef max
#define max(a,b)            (((a) > (b)) ? (a) : (b))
#endif

#ifndef min
#define min(a,b)            (((a) < (b)) ? (a) : (b))
#endif

#endif  /* NOMINMAX */

竞天问 2013-01-30
  • 打赏
  • 举报
回复
引用 13 楼 zhaokai115 的回复:
C/C++ code?1#define NO_MINMAX
这是哪个版本的? 在VS2012Update1这个问题已经解决了
竞天问 2013-01-30
  • 打赏
  • 举报
回复
引用 15 楼 aj3423 的回复:
约束编程,如果我碰到这种问题 我会找一个c++的约束编程库,这样就同时有c++和Prolog的特长了
好,约束编程,学习了
aj3423 2013-01-30
  • 打赏
  • 举报
回复
约束编程,如果我碰到这种问题 我会找一个c++的约束编程库,这样就同时有c++和Prolog的特长了
zhaokai115 2013-01-29
  • 打赏
  • 举报
回复
#define NO_MINMAX
BeanJoy 2013-01-26
  • 打赏
  • 举报
回复
大家一致认为,不允许B参加。
竞天问 2013-01-26
  • 打赏
  • 举报
回复
引用 11 楼 BeanJoy 的回复:
十个人排队,甲不能站中间,不能站两端,还得和乙挨着,还得和丙隔两个人,还得站丁后面。 经过激烈的讨论,大家一致认为:让甲滚!
明白你的意思了。 不过C和D也有两个限制条件的
BeanJoy 2013-01-26
  • 打赏
  • 举报
回复
十个人排队,甲不能站中间,不能站两端,还得和乙挨着,还得和丙隔两个人,还得站丁后面。 经过激烈的讨论,大家一致认为:让甲滚!
竞天问 2013-01-26
  • 打赏
  • 举报
回复
引用 9 楼 BeanJoy 的回复:
大家一致认为,不允许B参加。
为什么
竞天问 2013-01-25
  • 打赏
  • 举报
回复
那个undef max的问题在VS2012的Update1里解决了…… MS啊
竞天问 2013-01-25
  • 打赏
  • 举报
回复
引用 6 楼 Only_phantasy 的回复:
我明白你的意思了,你说的是解这一个题目的方法。 我写的东西是可以应付这一类的问题的。 比如变量个数变了,每个变量可取的状态也多了等等,用这个类都可以解决。 其实我的代码里把2状态的情况做了模板偏特化,也是用的二进制。
I'm Daniel Du 2013-01-25
  • 打赏
  • 举报
回复
引用 4 楼 JingTianWen 的回复:
引用 3 楼 Only_phantasy 的回复: 利用二进制压缩状态,对1~2^6-1之间的值逐个判断也不失为一个可行办法。 为什么是6次方? 其实我没明白你说的啥意思……
#include<cstdio>
using namespace std;

int pow(int a)
{
    if(a==0)return 1;
    else return 2*pow(a-1);
}

void HaveFun()
{
    for(int i=0;i<=pow(6)-1;i++)
        if(i&0x10?(i&0x8?1:0):1)
            if(i&0x4 || i&0x2)
                if(i&0x2 && i&0x1 || !(i&0x2 && i&0x1)){
                    int amount=2;
                    for(int offset=0;offset<=4;offset++)
                        if(i&1<<offset)amount--;
                    if(amount>=0)printf("%d\n",i);
                }
}

int main()
{
    HaveFun();
    getchar();
    return 0;
}
大概就是这个意思啦,不知道我有没有理解错题目意思。 您程序的代码风格不错啊,暂时没详细看,等我看完会给您提出建议的
竞天问 2013-01-25
  • 打赏
  • 举报
回复
引用 2 楼 Only_phantasy 的回复:
引用 1 楼 JingTianWen 的回复:是不是大家都不喜欢看这么长的代码? 代码不是一瞬间就能看完的啊。。。楼主难道在线等评价?
我是想有人给提点意见啥的,编码风格啊,实现方法啊都可以的
竞天问 2013-01-25
  • 打赏
  • 举报
回复
引用 3 楼 Only_phantasy 的回复:
利用二进制压缩状态,对1~2^6-1之间的值逐个判断也不失为一个可行办法。
为什么是6次方? 其实我没明白你说的啥意思……
I'm Daniel Du 2013-01-25
  • 打赏
  • 举报
回复
利用二进制压缩状态,对1~2^6-1之间的值逐个判断也不失为一个可行办法。
I'm Daniel Du 2013-01-25
  • 打赏
  • 举报
回复
引用 1 楼 JingTianWen 的回复:
是不是大家都不喜欢看这么长的代码?
代码不是一瞬间就能看完的啊。。。楼主难道在线等评价?
竞天问 2013-01-25
  • 打赏
  • 举报
回复
是不是大家都不喜欢看这么长的代码?

5,530

社区成员

发帖
与我相关
我的任务
社区描述
C/C++ 模式及实现
社区管理员
  • 模式及实现社区
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧