Street Fighter hdoj3927

 最小支配集问题,还有一个限制就是每个人只能选一次, 所以既是重复覆盖,又是精确覆盖,是Dancing Links的综合应用.

remove1为精确覆盖删除,remove2为重复覆盖删除, 一定要注意删除的顺序。


#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cmath>
#include <queue>
#include <algorithm>
#include <vector>
#include <cstring>
#include <stack>
#include <cctype>
#include <utility>   
#include <map>
#include <string>  
#include <climits> 
#include <set>
#include <string>    
#include <sstream>
#include <utility>   
#include <ctime>
#include <bitset>

using std::priority_queue;
using std::vector;
using std::swap;
using std::stack;
using std::sort;
using std::max;
using std::min;
using std::pair;
using std::map;
using std::string;
using std::cin;
using std::cout;
using std::set;
using std::queue;
using std::string;
using std::stringstream;
using std::make_pair;
using std::getline;
using std::greater;
using std::endl;
using std::multimap;
using std::deque;
using std::unique;
using std::lower_bound;
using std::random_shuffle;
using std::bitset;
using std::upper_bound;
using std::multiset;

typedef long long LL;
typedef unsigned long long ULL;
typedef pair<int, int> PAIR;
typedef multimap<int, int> MMAP;
typedef LL TY;
typedef long double LF;

const int MAXN(110);
const int MAXM(110);
const int MAXE(10010);
const int MAXK(6);
const int HSIZE(31313);
const int SIGMA_SIZE(26);
const int MAXH(13);
const int INFI((INT_MAX-1) >> 1);
const ULL BASE(31);
const LL LIM(10000000);
const int INV(-10000);
const int MOD(20100403);
const double EPS(1e-7);
const LF PI(acos(-1.0));

template<typename T> void checkmax(T &a, T b){if(b > a) a = b;}
template<typename T> void checkmin(T &a, T b){if(b < a) a = b;}
template<typename T> T ABS(const T &a){return a < 0? -a: a;}

int M, ans;

struct DANCING_LINKS
{
    int H[MAXN];
    int S[MAXM];
    int L[MAXE], U[MAXE], R[MAXE], D[MAXE], C[MAXE];
    bool vis[MAXM];
    int size;
    void init(int n, int m)
    {
        for(int i = 0; i <= n; ++i) H[i] = -1;
        for(int i = 0; i <= m; ++i)
        {
            S[i] = 0;
            U[i] = D[i] = C[i] = i;
            L[i+1] = i;
            R[i] = i+1;
        }
        L[0] = m;
        R[m] = 0;
        size = m+1;
    }
    void link(int r, int c)
    {
        ++S[C[size] = c];
        D[size] = D[c];
        U[D[c]] = size;
        U[size] = c;
        D[c] = size;
        if(H[r] == -1) L[size] = R[size] = H[r] = size;
        {
            R[size] = R[H[r]];
            L[R[H[r]]] = size;
            L[size] = H[r];
            R[H[r]] = size;
        }
        ++size;
    }
    void remove1(int c)
    {
        L[R[c]] = L[c];
        R[L[c]] = R[c];
        for(int i = D[c]; i != c; i = D[i])
            for(int j = R[i]; j != i; j = R[j])
            {
                --S[C[j]];
                U[D[j]] = U[j];
                D[U[j]] = D[j];
            }
    }
    void resume1(int c)
    {
        L[R[c]] = R[L[c]] = c;
        for(int i = U[c]; i != c; i = U[i])
            for(int j = L[i]; j != i; j = L[j])
            {
                ++S[C[j]];
                U[D[j]] = D[U[j]] = j;
            }
    }
    void remove2(int c)
    {
        for(int i = D[c]; i != c; i = D[i])
        {
            L[R[i]] = L[i];
            R[L[i]] = R[i];
        }
    }
    void resume2(int c)
    {
        for(int i = U[c]; i != c; i = U[i])
            L[R[i]] = R[L[i]] = i;
    }
    int h()
    {
        int ret = 0;
        for(int i = R[0]; i && i <= M; i = R[i]) vis[i] = false;
        for(int i = R[0]; i && i <= M; i = R[i])
            if(!vis[i])
            {
                ++ret;
                vis[i] = true;
                for(int j = D[i]; j != i; j = D[j])
                    for(int k = R[j]; k != j; k = R[k])
                        vis[C[k]] = true;
            }
        return ret;
    }
    void dfs(int dep)
    {
        if(dep+h() >= ans) return;
        int c, sz = INFI;
        for(int i = R[0]; i && i <= M; i = R[i])
            if(S[i] < sz)
            {
                c = i;
                sz = S[i];
            }
        if(sz == INFI)
        {
            ans = dep;
            return;
        }
        for(int i = D[c]; i != c; i = D[i])
        {
            for(int j = R[i]; j != i; j = R[j])
                if(C[j] <= M) remove2(j);
            remove2(i);
            for(int j = R[i]; j != i; j = R[j])
                if(C[j] > M) remove1(C[j]);
            dfs(dep+1);
            for(int j = L[i]; j != i; j = L[j])
                if(C[j] > M) resume1(C[j]);
            resume2(i);
            for(int j = L[i]; j != i; j = L[j])
                if(C[j] <=  M) resume2(j);
        }
    }
} dlx;

int cnt[30];
int num[30][2];
vector<PAIR> beat[30][2];

int main()
{
    int TC, n_case(0);
    scanf("%d", &TC);
    while(TC--)
    {
        int n;
        scanf("%d", &n);
        for(int i = 0; i < n; ++i)
        {
            beat[i][0].clear();
            beat[i][1].clear();
        }
        M = 0;
        for(int i = 0; i < n; ++i)
        {
            scanf("%d", cnt+i);
            M += cnt[i];
            for(int j = 0; j < cnt[i]; ++j)
            {
                int K, a, b;
                scanf("%d", &K);
                for(int k = 0; k < K; ++k)
                {
                    scanf("%d%d", &a, &b);
                    beat[i][j].push_back(make_pair(a, b));
                }
            }
        }
        dlx.init(M, M+n);
        int ind = 0;
        for(int i = 0; i < n; ++i)
            for(int j = 0; j < cnt[i]; ++j)
                num[i][j] = ++ind;
        for(int i = 0; i < n; ++i)
            for(int j = 0; j < cnt[i]; ++j)
            {
                dlx.link(num[i][j], M+i+1);
                for(int k = 0; k < cnt[i]; ++k)
                    dlx.link(num[i][j], num[i][k]);
                for(int k = 0; k < beat[i][j].size(); ++k)
                    dlx.link(num[i][j], num[beat[i][j][k].first][beat[i][j][k].second]);
            }
        ans = INFI;
        dlx.dfs(0);
        printf("Case %d: %d\n", ++n_case, ans);
    }
    return 0;
}




你可能感兴趣的:(Street Fighter hdoj3927)