hdu - 3498 - whosyourdaddy(重复覆盖DLX)

题意:N(2 ≤ N ≤ 55)个点,M(0 ≤ M ≤ N*N)条无向边,删除一个点会把与其相邻的点一起删掉,问最少删几次可以删掉所有点。

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=3498

——>>N个点看成 N 个要被覆盖的列,每个点作为一行,与其相邻的点的位置在这一行中标为 1,还有它自已的位置也标记为 1。。

这就是经典的重复覆盖问题了。。于是,DLX上场。。

#include <cstdio>
#include <cstring>

const int MAXR = 55 + 10;
const int MAXC = 55 + 10;
const int MAXNODE = MAXR * MAXC;
const int INF = 0x3f3f3f3f;

struct DLX
{
    int sz;
    int H[MAXR], S[MAXC];
    int row[MAXNODE], col[MAXNODE];
    int U[MAXNODE], D[MAXNODE], L[MAXNODE], R[MAXNODE];
    int Min;

    void Init(int n)
    {
        for (int i = 0; i <= n; ++i)
        {
            U[i] = D[i] = i;
            L[i] = i - 1;
            R[i] = i + 1;
        }
        L[0] = n;
        R[n] = 0;

        sz = n + 1;
        memset(S, 0, sizeof(S));
        memset(H, -1, sizeof(H));
    }

    void Link(const int& r, const int& c)
    {
        row[sz] = r;
        col[sz] = c;
        D[sz] = D[c];
        U[D[c]] = sz;
        D[c] = sz;
        U[sz] = c;
        if (H[r] == -1)
        {
            H[r] = L[sz] = R[sz] = sz;
        }
        else
        {
            R[sz] = R[H[r]];
            L[R[H[r]]] = sz;
            R[H[r]] = sz;
            L[sz] = H[r];
        }
        S[c]++;
        sz++;
    }

    void Remove(const int& c)
    {
        for (int i = D[c]; i != c; i = D[i])
        {
            L[R[i]] = L[i];
            R[L[i]] = R[i];
        }
    }

    void Restore(const int& c)
    {
        for (int i = U[c]; i != c; i = U[i])
        {
            L[R[i]] = i;
            R[L[i]] = i;
        }
    }

    int A()
    {
        int ret = 0;
        bool vis[MAXC];

        memset(vis, 0, sizeof(vis));
        for (int i = R[0]; i != 0; i = R[i])
        {
            if (!vis[i])
            {
                vis[i] = true;
                ++ret;
                for (int j = D[i]; j != i; j = D[j])
                {
                    for (int k = R[j]; k != j; k = R[k])
                    {
                        vis[col[k]] = true;
                    }
                }
            }
        }

        return ret;
    }

    void Dfs(int cur)
    {
        if (cur + A() >= Min) return;

        if (R[0] == 0)
        {
            if (cur < Min)
            {
                Min = cur;
            }
            return;
        }

        int c = R[0];
        for (int i = R[0]; i != 0; i = R[i])
        {
            if (S[i] < S[c])
            {
                c = i;
            }
        }

        for (int i = D[c]; i != c; i = D[i])
        {
            Remove(i);
            for (int j = R[i]; j != i; j = R[j])
            {
                Remove(j);
            }
            Dfs(cur + 1);
            for (int j = L[i]; j != i; j = L[j])
            {
                Restore(j);
            }
            Restore(i);
        }
    }

    void Solve()
    {
        Min = INF;
        Dfs(0);
        printf("%d\n", Min);
    }

} dlx;

int N, M;

void Read()
{
    int a, b;

    dlx.Init(N);
    while (M--)
    {
        scanf("%d%d", &a, &b);
        dlx.Link(a, b);
        dlx.Link(b, a);
    }
    for (int i = 1; i <= N; ++i)
    {
        dlx.Link(i, i);
    }
}

int main()
{
    while (scanf("%d%d", &N, &M) == 2)
    {
        Read();
        dlx.Solve();
    }

    return 0;
}
时间: 2024-10-12 18:44:48

hdu - 3498 - whosyourdaddy(重复覆盖DLX)的相关文章

[DLX重复覆盖] hdu 3498 whosyourdaddy

题意: 给N个怪,M个关系. 每个关系代表a和b是邻居. 然后问每次攻击你可以攻击一个怪以及它的全部邻居 问最少需要几次攻击能把怪全部杀死. 思路: 怪为行和列,然后对面每个怪的邻居都是这个怪的列建图. 也是比较裸的重复覆盖. 代码: #include"cstdlib" #include"cstdio" #include"cstring" #include"cmath" #include"queue" #i

hdu - 4979 - A simple math problem.(可重复覆盖DLX + 打表)

题意:一种彩票共有 N 个号码,每注包含 M 个号码,如果开出来的 M 个号码中与自己买的注有 R 个以上的相同号码,则中二等奖,问要保证中二等奖至少要买多少注(1<=R<=M<=N<=8). 题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4979 -->>覆盖问题,yy可知是可重复覆盖问题,于是,DLX 上场.. N个 选 R 个,共有 C[N][R] 种选法,每种选法需要被覆盖,对应于 DLX 中的列.. N个 选 M

hdu - 3498 - whosyourdaddy(反复覆盖DLX)

题意:N(2 ≤ N ≤ 55)个点,M(0 ≤ M ≤ N*N)条无向边,删除一个点会把与其相邻的点一起删掉.问最少删几次能够删掉全部点. 题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=3498 -->>N个点看成 N 个要被覆盖的列,每一个点作为一行,与其相邻的点的位置在这一行中标为 1,还有它自已的位置也标记为 1.. 这就是经典的反复覆盖问题了..于是,DLX上场.. #include <cstdio> #include &l

hdu 2295 Radar 重复覆盖+二分

题目链接 给m个雷达, n个城市, 以及每个城市的坐标, m个雷达里只能使用k个, 在k个雷达包围所有城市的前提下, 求最小半径. 先求出每个雷达到所有城市的距离, 然后二分半径, 如果距离小于二分的值, 就加边(大概不叫加边, 我也不知道叫什么...... #include<bits/stdc++.h> using namespace std; #define pb(x) push_back(x) #define ll long long #define mk(x, y) make_pair

DLX精确覆盖与重复覆盖模板题

hihoCoder #1317 : 搜索四·跳舞链 原题地址:http://hihocoder.com/problemset/problem/1317 时间限制:10000ms 单点时限:1000ms 内存限制:256MB   描述 小Ho最近遇到一个难题,他需要破解一个棋局. 棋局分成了n行,m列,每行有若干个棋子.小Ho需要从中选择若干行使得每一列有且恰好只有一个棋子. 比如下面这样局面: 其中1表示放置有棋子的格子,0表示没有放置棋子. 对于上面这个问题,小Ho经过多次尝试以后得到了解为选

UVA - 11214 Guarding the Chessboard (可重复覆盖,DLX+IDA*)

题目链接 正解是IDA*+四个方向判重,但由于是个裸的可重复覆盖问题,可以用DLX水过~ 每个格子与放上皇后能干掉的标记连边,跑可重复覆盖DLX.注意要用IDA*来优化,否则会超时. 1 #include<bits/stdc++.h> 2 using namespace std; 3 typedef long long ll; 4 const int N=10+2; 5 int n,m,np,ka; 6 char s[N][N]; 7 struct P {int x,y;} p[N*N]; 8

HDU 5046 Airport(DLX可重复覆盖)

Problem Description The country of jiuye composed by N cites. Each city can be viewed as a point in a two- dimensional plane with integer coordinates (x,y). The distance between city i and city j is defined by dij = |xi - xj| + |yi - yj|. jiuye want

HDU 5046 Airport(DLX重复覆盖)

HDU 5046 Airport 题目链接 题意:给定一些机场,要求选出K个机场,使得其他机场到其他机场的最大值最小 思路:二分+DLX重复覆盖去判断即可 代码: #include <cstdio> #include <cstring> using namespace std; const int MAXNODE = 4005; const int MAXM = 65; const int MAXN = 65; const int INF = 0x3f3f3f3f; int K;

HDU 3335 Divisibility(DLX可重复覆盖)

Problem Description As we know,the fzu AekdyCoin is famous of math,especially in the field of number theory.So,many people call him "the descendant of Chen Jingrun",which brings him a good reputation. AekdyCoin also plays an important role in th