//
// Created by Running Photon on 2016-2-29
// Copyright (c) 2015 Running Photon. All rights reserved.
//
#include <algorithm>
#include <cctype>
#include <cmath>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <iomanip>
#include <iostream>
#include <map>
#include <queue>
#include <string>
#include <sstream>
#include <set>
#include <vector>
#include <stack>
#define ALL(x) x.begin(), x.end()
#define INS(x) inserter(x, x,begin())
#define ll long long
#define CLR(x) memset(x, 0, sizeof x)
using namespace std;
const int inf = 0x3f3f3f3f;
const int MOD = 1e9 + 7;
const int maxn = 1e6 + 10;
const int maxv = 1e2 + 10;
const double eps = 1e-9;
/*
设有集合state1和state2
state1的01串,如果当前位置是1就表示当前位还没被化简掉,如果是0就表示当前位已经被化简掉
state2的01串。如果当前位置是1,就表示他本身,如果是0,就表示取反(就是A和!A)
dp[state1][state2]数组存的是当前状态是否存在
have[state1][state2]用来记录答案当前状态是否已经被跟高维度(消的元素越多维度越高)利用
如果被利用,那么这个状态就可以省略的 记录为0
如果没有比他高维的状态利用他,记录为1
最后答案就是枚举have的所有可能 并且是1就输出
*/
int dp[(1 << 10) + 5][(1 << 10) + 5];
int have[(1 << 10) + 5][(1 << 10) + 5];
int state[(1 << 10) + 5];
int n, len;
int dfs(int nan, int cur) {
///记忆化操作
if(dp[nan][cur] != -1) return dp[nan][cur];
///判断当前状态是不是已经是最底层(叶子节点)
if(nan == (1 << len) - 1) {
if(state[cur])
have[nan][cur] = 1;
// printf("cur = %d res = %d\n", cur, state[cur]);
return dp[nan][cur] = state[cur];
}
///先初始化当前状态不能被组合出来
int flag = 0;
for(int i = 0; i < len; i++) { ///枚举可以消的每一位
if((1 << i) & nan) continue; ///如果为1则表示当前位不能被消
int nnan = nan ^ (1 << i); ///nan 是从nnan状态转移过来的
///此处模拟消的过程,消的规则就是,只有一位不同
int f1 = dfs(nnan, cur); ///当前状态是否存在
int f2 = dfs(nnan, cur ^ (1 << i)); ///当前位取反后是否存在;
if(f1 && f2) {
///为了只输出一种结果,分析可知,当它的右儿子(就是cur ^ (1 << i))和左儿子(cur)都没有被其他的状态吸收的时候,当前状态才有输出价值
if(have[nnan][cur ^ (1 << i)] || have[nnan][cur])
have[nan][cur] = 1;
have[nnan][cur] = have[nnan][cur ^ (1 << i)] = 0;
///当前位合法,所以他的两个子状态被吸取 不用输出,have置0
// printf("have[%d][%d] = 0\n", nnan, cur, have[nnan][cur]);
// printf("have[%d][%d] = %d\n", nan, cur, have[nan][cur]);
flag = 1;
// return dp[nan][cur] = flag;
}
}
///返回当前状态是否存在
return dp[nan][cur] = flag;
}
void print(int i, int j, int& cas) {
if(cas++) printf(" + ");
for(int k = len - 1; ~k; k--) {
if(!((1 << k) & i)) continue;
if((1 << k) & j) {
printf("%c", 'A' + len - 1 - k);
}
else printf("!%c", 'A' + len - 1 - k);
}
}
int main() {
//#ifdef LOCAL
freopen("in.txt", "r", stdin);
// freopen("out.txt","w",stdout);
//#endif
// ios_base::sync_with_stdio(0);
///n表示有n个最小项,len表示有len个元素(此程序处理范围为len <= 10)
while(scanf("%d%d", &n, &len) != EOF && n && len) { ///输入最小项个数n和元素个数len
///分别输入n个最小项,0表示非,1表示(默认从左到右是A, B, C...)
CLR(state);
for(int i = 0; i < n; i++) {
int tmp = 0;
for(int j = 0; j < len; j++) {
int x;
scanf("%1d", &x);
///state数组表示输入的状态。
tmp = tmp * 2 + x;
}
// printf("tmp = %d\n", tmp);
state[tmp] = 1;
}
///将所有状态初始化为-1,表示未访问过,用来记忆化搜索,减少时间消耗
memset(dp, -1, sizeof dp);
///have 数组初始化为0
CLR(have);
///如果所有元素都被消掉了,那说明是恒成立之类的时间,
if(dfs(0, 0)) {printf("result is 1"); continue;}
int cas = 0;
for(int i = 0; i < 1 << len; i++) {
if(have[i][0]) {
print(i, 0, cas);
}
for(int j = i; j; j = (j - 1) & i) { ///二进制枚举子集
if(have[i][j]) {
print(i, j, cas);
}
}
}
puts("");
}
return 0;
}
利用动态规划将逻辑函数化简到最简形式
最新推荐文章于 2021-05-18 05:02:56 发布