利用動態規劃將邏輯函數化簡到最簡形式

//
//  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;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章