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


    hihoCoder #1317 : 搜索四·跳舞链

    原题地址:http://hihocoder.com/problemset/problem/1317

    时间限制:10000ms

    单点时限:1000ms

    内存限制:256MB

     

    描述

    小Ho最近遇到一个难题,他需要破解一个棋局。

    棋局分成了n行,m列,每行有若干个棋子。小Ho需要从中选择若干行使得每一列有且恰好只有一个棋子。

    比如下面这样局面:

             

    其中1表示放置有棋子的格子,0表示没有放置棋子。

            

    对于上面这个问题,小Ho经过多次尝试以后得到了解为选择2、3、4行就可以做到。

    但是小Ho觉得自己的方法不是太好,于是他求助于小Hi。

    小Hi:小Ho你是怎么做的呢?

    小Ho:我想每一行都只有两种状态,选中和未被选中。那么我将选中视为1,未选中视为0。则每一种组合恰好对应了一个4位的01串,也就是一个4位的二进制数。

    小Hi:恩,没错。

    小Ho:然后我所做的就是去枚举每一个二进制数然后再来判定是否满足条件。

    小Hi:小Ho你这个做法本身没什么问题,但是对于棋盘行数再多一点的情况就不行了。

    小Ho:恩,我也这么觉得,那你有什么好方法么?

    小Hi:我当然有了,你听我慢慢道来。

    提示:跳舞链

    输入

    第1行:1个正整数t,表示数据组数,1≤t≤10。

    接下来t组数据,每组的格式为:

    第1行:2个正整数n,m,表示输入数据的行数和列数。2≤n,m≤100。

    第2..n+1行:每行m个数,只会出现0或1。

    输出

    第1..t行:第i行表示第i组数据是否存在解,若存在输出"Yes",否则输出"No"。

    样例输入

    2

    4 4

    1 1 0 1

    0 1 1 0

    1 0 0 0

    0 1 0 1

    4 4

    1 0 1 0

    0 1 0 0

    1 0 0 0

    0 0 1 1

    样例输出

    No

    Yes

     

    DLX精确覆盖

    #include <algorithm>
    #include <cstring>
    #include <string.h>
    #include <iostream>
    #include <list>
    #include <map>
    #include <set>
    #include <stack>
    #include <string>
    #include <utility>
    #include <queue>
    #include <vector>
    #include <cstdio>
    #include <cmath>
    
    #define LL long long
    
    using namespace std;
    
    const int maxnode = 100010; //最多多少个‘1’
    const int MaxM = 1010;
    const int MaxN = 1010;
    
    struct DLX
    {
        int n,m,SIZE;
        int U[maxnode],D[maxnode],R[maxnode],L[maxnode],Row[maxnode],Col[maxnode];//L,R,D,U四个数组记录某节点上下左右邻居
        int H[MaxN], S[MaxM];//H记录排头,S记录某列有多少个节点
        int ansd, ans[MaxN]; 
        void init(int _n,int _m)
        {
            n = _n;
            m = _m;
            for(int i = 0;i <= m;i++)
            {
                S[i] = 0;
                U[i] = D[i] = i;
                L[i] = i-1;
                R[i] = i+1;
            }
            R[m] = 0; L[0] = m;
            SIZE = m;
            for(int i = 1;i <= n;i++)
                H[i] = -1;
        }
        void Link(int r,int c)
        {
            ++S[Col[++SIZE]=c];
            Row[SIZE] = r;
            D[SIZE] = D[c];
            U[D[c]] = SIZE;
            U[SIZE] = c;
            D[c] = SIZE;
            if(H[r] < 0)H[r] = L[SIZE] = R[SIZE] = SIZE;
            else
            {
                R[SIZE] = R[H[r]];
                L[R[H[r]]] = SIZE;
                L[SIZE] = H[r];
                R[H[r]] = SIZE;
            }
        }
        void exact_Remove(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])
                {
                    U[D[j]] = U[j];
                    D[U[j]] = D[j];
                    --S[Col[j]];
                }
        }
        void repeat_remove(int c) {
        for(int i = D[c]; i != c; i = D[i])
            L[R[i]] = L[i], R[L[i]] = R[i];
        }
        void repeat_resume(int c) {
        for(int i = U[c]; i != c; i = U[i])
            L[R[i]] = R[L[i]] = i;
        }
    
        int f() { //估价函数。
        bool vv[MaxM];
        int ret = 0, c, i, j;
        for(c = R[0]; c != 0; c = R[c]) vv[c] = 1;
        for(c = R[0]; c != 0; c = R[c])
            if(vv[c]) {
                ++ret, vv[c] = 0;
                for(i = D[c]; i != c; i = D[i])
                    for(j = R[i]; j != i; j = R[j])
                        vv[Col[j]] = 0;
            }
        return ret;
        }
    
        void repeat_dance(int d) {
        if(d + f() >= ansd) return; //估价函数剪枝,A*搜索
        if(R[0] == 0) {
            if(d < ansd) ansd = d;
            return;
        }
        int c = R[0], i, j;
        for(i = R[0]; i; i = R[i])
            if(S[i] < S[c]) c = i;
        for(i = D[c]; i != c; i = D[i]) {
            repeat_remove(i);
            for(j = R[i]; j != i; j = R[j]) repeat_remove(j);
            repeat_dance(d + 1);
            for(j = L[i]; j != i; j = L[j]) repeat_resume(j);
            repeat_resume(i);
        }
    }
        void exact_resume(int c)
        {
            for(int i = U[c];i != c;i = U[i])
                for(int j = L[i];j != i;j = L[j])
                    ++S[Col[U[D[j]]=D[U[j]]=j]];
            L[R[c]] = R[L[c]] = c;
        }
        //d为递归深度
        bool exact_Dance(int d)
        {
            if(R[0] == 0)
            {
                ansd = d;
                return true;
            }
            int c = R[0];
            for(int i = R[0];i != 0;i = R[i])
                if(S[i] < S[c])
                    c = i;
            exact_Remove(c);
            for(int i = D[c];i != c;i = D[i])
            {
                ans[d] = Row[i];
                for(int j = R[i]; j != i;j = R[j]) exact_Remove(Col[j]);
                if(exact_Dance(d+1))return true;
                for(int j = L[i]; j != i;j = L[j]) exact_resume(Col[j]);
            }
            exact_resume(c);
            return false;
        }
    };
    
    DLX g;
    int main()
    {
        int n,m;
        int t;
        cin>>t;
    
        while( t--)
        {
            scanf("%d%d",&n,&m);
            g.init(n,m);
            for(int i = 1;i <= n;i++)
            {
                int num;
                for(int j=1;j<=m;j++)
                    {
                        scanf("%d",&num);
                        if(num==1) g.Link(i,j);
                    }
            }
            if(!g.exact_Dance(0))printf("No
    ");
            else
                printf("Yes
    ");
        }
        return 0;
    }

    HDU 3498 whosyourdaddy

    http://acm.hdu.edu.cn/showproblem.php?pid=3498

     

    whosyourdaddy

    Time Limit: 20000/10000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others)
    Total Submission(s): 1686    Accepted Submission(s): 841

    Problem Description

    sevenzero liked Warcraft very much, but he haven't practiced it for several years after being addicted to algorithms. Now, though he is playing with computer, he nearly losed and only his hero Pit Lord left. sevenzero is angry, he decided to cheat to turn defeat into victory. So he entered "whosyourdaddy", that let Pit Lord kill any hostile unit he damages immediately. As all Warcrafters know, Pit Lord masters a skill called Cleaving Attack and he can damage neighbour units of the unit he attacks. Pit Lord can choice a position to attack to avoid killing partial neighbour units sevenzero don't want to kill. Because sevenzero wants to win as soon as possible, he needs to know the minimum attack times to eliminate all the enemys.

     

     

    Input

    There are several cases. For each case, first line contains two integer N (2 ≤ N ≤ 55) and M (0 ≤ M ≤ N*N),and N is the number of hostile units. Hostile units are numbered from 1 to N. For the subsequent M lines, each line contains two integers A and B, that means A and B are neighbor. Each unit has no more than 4 neighbor units. The input is terminated by EOF.

     

     

    Output

    One line shows the minimum attack times for each case.

     

     

    Sample Input

    5 4
    1 2
    1 3
    2 4
    4 5
    6 4
    1 2
    1 3
    1 4
    4 5

     

     

    Sample Output

    2
    3

     

     

    Author

    sevenzero

     

     

    Source

    2010 ACM-ICPC Multi-University Training Contest(7)——Host by HIT

    DLX重复覆盖

    n个敌对单元,m对单元互相相邻,建图的邻接矩阵,DLX。

    #include <algorithm>
    #include <cstring>
    #include <string.h>
    #include <iostream>
    #include <list>
    #include <map>
    #include <set>
    #include <stack>
    #include <string>
    #include <utility>
    #include <queue>
    #include <vector>
    #include <cstdio>
    #include <cmath>
    
    #define LL long long
    
    using namespace std;
    
    const int maxnode = 100010; //最多多少个1
    const int MaxM = 1010;
    const int MaxN = 1010;
    
    struct DLX
    {
        int n,m,SIZE;
        int U[maxnode],D[maxnode],R[maxnode],L[maxnode],Row[maxnode],Col[maxnode];//L,R,D,U四个数组记录某节点上下左右邻居
        int H[MaxN], S[MaxM];//H记录行头,S记录某列有多少个节点
        int ansd, ans[MaxN];
        void init(int _n,int _m)
        {
            n = _n;
            m = _m;
            for(int i = 0;i <= m;i++)
            {
                S[i] = 0;
                U[i] = D[i] = i;
                L[i] = i-1;
                R[i] = i+1;
            }
            R[m] = 0; L[0] = m;
            SIZE = m;
            for(int i = 1;i <= n;i++)
                H[i] = -1;
        }
        void Link(int r,int c)
        {
            ++S[Col[++SIZE]=c];
            Row[SIZE] = r;
            D[SIZE] = D[c];
            U[D[c]] = SIZE;
            U[SIZE] = c;
            D[c] = SIZE;
            if(H[r] < 0)H[r] = L[SIZE] = R[SIZE] = SIZE;
            else
            {
                R[SIZE] = R[H[r]];
                L[R[H[r]]] = SIZE;
                L[SIZE] = H[r];
                R[H[r]] = SIZE;
            }
        }
        void exact_Remove(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])
                {
                    U[D[j]] = U[j];
                    D[U[j]] = D[j];
                    --S[Col[j]];
                }
        }
        void repeat_remove(int c) {
        for(int i = D[c]; i != c; i = D[i])
            L[R[i]] = L[i], R[L[i]] = R[i];
        }
        void repeat_resume(int c) {
        for(int i = U[c]; i != c; i = U[i])
            L[R[i]] = R[L[i]] = i;
        }
    
        int f() { //估价函数。
        bool vv[MaxM];
        int ret = 0, c, i, j;
        for(c = R[0]; c != 0; c = R[c]) vv[c] = 1;
        for(c = R[0]; c != 0; c = R[c])
            if(vv[c]) {
                ++ret, vv[c] = 0;
                for(i = D[c]; i != c; i = D[i])
                    for(j = R[i]; j != i; j = R[j])
                        vv[Col[j]] = 0;
            }
        return ret;
        }
    
        void repeat_dance(int d) {
        if(d + f() >= ansd) return; //估价函数剪枝,A*搜索
        if(R[0] == 0) {
            if(d < ansd) ansd = d;
            return;
        }
        int c = R[0], i, j;
        for(i = R[0]; i; i = R[i])
            if(S[i] < S[c]) c = i;
        for(i = D[c]; i != c; i = D[i]) {
            repeat_remove(i);
            for(j = R[i]; j != i; j = R[j]) repeat_remove(j);
            repeat_dance(d + 1);
            for(j = L[i]; j != i; j = L[j]) repeat_resume(j);
            repeat_resume(i);
        }
    }
        void exact_resume(int c)
        {
            for(int i = U[c];i != c;i = U[i])
                for(int j = L[i];j != i;j = L[j])
                    ++S[Col[U[D[j]]=D[U[j]]=j]];
            L[R[c]] = R[L[c]] = c;
        }
        //d为递归深度
        bool exact_Dance(int d)
        {
            if(R[0] == 0)
            {
                ansd = d;
                return true;
            }
            int c = R[0];
            for(int i = R[0];i != 0;i = R[i])
                if(S[i] < S[c])
                    c = i;
            exact_Remove(c);
            for(int i = D[c];i != c;i = D[i])
            {
                ans[d] = Row[i];
                for(int j = R[i]; j != i;j = R[j]) exact_Remove(Col[j]);
                if(exact_Dance(d+1))return true;
                for(int j = L[i]; j != i;j = L[j]) exact_resume(Col[j]);
            }
            exact_resume(c);
            return false;
        }
    };
    
    DLX dlx;
    int main()
    {
        int n,m;
        while(scanf("%d%d",&n,&m)!=EOF)
        {
            dlx.init(n,n);
            while(m--)
            {
                int a,b;
                scanf("%d%d",&a,&b);
                dlx.Link(a,b);
                dlx.Link(b,a);
            }
            for(int i=1;i<=n;i++)dlx.Link(i,i);
            dlx.ansd=0x3f3f3f;
            dlx.repeat_dance(0);
            printf("%d
    ",dlx.ansd);
        }
        return 0;
    }
  • 相关阅读:
    PHP编程中一些时间和日期代码调用的实例
    想不显示织梦栏目列表页缩略图就是不显示默认缩略图怎么办
    织梦dede文章增加HTML自定义字段字符被过滤问题
    Dedecms友情链接/uploads/fli<x>nk/不显示正确的图片路径错误
    Dedecms教程:整站调用购物车订单数量简单解决办法
    织梦DedeCMS模板常用的内容统计sql标签代码
    DEDECMS首页loop调用留言本带用户头像的方法
    Python 序列、列表(List)、元组(Tuple)
    Python 字符串常用函数
    Python 运算符
  • 原文地址:https://www.cnblogs.com/smartweed/p/5877832.html
Copyright © 2020-2023  润新知