CF1105E Helping Hiasat

题目地址:CF1105E Helping Hiasat

首先将问题转化成图论:对每个人建立一个点,将同一次修改后的所有人代表的点两两连一条边,那么最终所求的就是这个图的最大独立集

我们知道最大独立集是NPC问题,只能暴力搜

裸暴力的时间复杂度为 \(O(2^m)\) ,由于 \(m\leq 40\) ,无法承受

我们知道最大独立集=补图最小团,考虑记忆化搜索,时间复杂度降为 \(O(\sqrt {2^m})\)

我写的代码广泛应用了STL,包括 \(vector\),\(set\),\(map\),\(string\),因此常数较大,时间复杂度也应该加上几个 \(log\) ,但巧妙应用可以降低编程复杂度

代码:

#include <bits/stdc++.h>
#define ll long long
#define si set<int>::iterator
using namespace std;
int n, m, num;
ll e[46];
vector<set<int> > v;
map<string, int> mp;
map<ll, int> f;

int dfs(ll x) {
    if (f.find(x) != f.end()) return f[x];
    int t = 0;
    while (!((x >> t) & 1)) ++t;
    int a = dfs(x ^ (1ll << t)), b = dfs(x & e[t]);
    return f[x] = max(a, b + 1);
}

int main() {
    cin >> n >> m;
    for (int i = 1; i <= n; i++) {
        int o;
        scanf("%d", &o);;
        if (o == 1) {
            set<int> st;
            v.push_back(st);
        } else {
            string s;
            cin >> s;
            if (mp.find(s) == mp.end()) mp[s] = num++;
            v.back().insert(mp[s]);
        }
    }
    fill(e, e + m, (1ll << m) - 1);
    for (unsigned int i = 0; i < v.size(); i++)
        for (si i1 = v[i].begin(); i1 != v[i].end(); i1++)
            for (si i2 = v[i].begin(); i2 != v[i].end(); i2++) {
                int x = *i1, y = *i2;
                e[x] &= ~(1ll << y);
            }
    f[0] = 0;
    cout << dfs((1ll << m) - 1) << endl;
    return 0;
}
上一篇:D3_book 11.2 stack


下一篇:Linux相关——记录gdb基本操作(持续更新)