zoukankan      html  css  js  c++  java
  • POJ 3740 DLX

    题意:给你一个01矩阵,然后求是否存在选择一些行,使得每一列的1的个数都为1。

    思路:貌似朴素的DFS也可以,加点剪枝就可以过。这里贴个DLX的模版。

    推荐博客:http://www.cppblog.com/notonlysuccess/archive/2009/07/10/89701.html

    这里讲的很详细。

    #include <set>
    #include <map>
    #include <stack>
    #include <cmath>
    #include <queue>
    #include <cstdio>
    #include <string>
    #include <vector>
    #include <iomanip>
    #include <cstring>
    #include <iostream>
    #include <algorithm>
    #define Max 2505
    #define FI first
    #define SE second
    #define ll long long
    #define PI acos(-1.0)
    #define inf 0x3fffffff
    #define LL(x) ( x << 1 )
    #define bug puts("here")
    #define PII pair<int,int>
    #define RR(x) ( x << 1 | 1 )
    #define mp(a,b) make_pair(a,b)
    #define mem(a,b) memset(a,b,sizeof(a))
    #define REP(i,s,t) for( int i = ( s ) ; i <= ( t ) ; ++ i )
    
    using namespace std;
    
    #define N 5555
    
    ///DLX
    int L[N] , R[N] , D[N] , U[N] ,S[N] , C[N] ,st[N] ;//S[] 表示这一列的点数。C[] 表示这个点位于那一列。
    int n , m , num , head ;
    
    void insert(int col , int pos){//在这一列插入序号为pos的点
        int now = col ;
        while(D[now] != col) now = D[now] ;
        D[now] = pos ;
        D[pos] = col ;
        U[pos] = now ;
        U[col] = pos ;
    }
    
    void init(){
        head = 0 ;
        R[head] = 1 ;L[head] = m ;
        for (int i = 1 ; i <= m ; i ++ ){//每一行的头指针
            if(i == 1)L[i] = head ;
            else L[i] = i - 1 ;
            if(i == m)R[i] = head ;
            else R[i] = i + 1 ;
            U[i] = i ;
            D[i] = i ;
            S[i] = 0 ;
            C[i] = i ;
        }
        num = m ;//已经插入m个节点
        int k ;
        for (int i = 1 ; i <= n ; i ++ ){
            mem(st ,0) ;
            for (int j = 1 ; j <= m ; j ++ ){
                scanf("%d",&k) ;
                if(!k)continue ;
                num ++ ;
                insert(j , num) ;
                if(st[0] == 0){//每行的第一个
                    L[num] = num ; R[num] = num ;
                }else{
                    L[num] = st[st[0]] ;
                    R[num] = st[1] ;
                    R[st[st[0]]] = num ;
                    L[st[1]] = num ;
                }
                st[++st[0]] = num ;
                C[num] = j ;
                S[j] ++ ;
            }
        }
    }
    
    void remove(const 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[C[j]] ;
            }
        }
    }
    
    void resume(const int &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]] = j ;
                D[U[j]] = j ;
            }
        }
        L[R[c]] = c ;
        R[L[c]] = c ;
    }
    
    int dfs(const int &k){
        if(R[head] == head)return 1 ;
        int MX = inf ,c ;
        for (int t = R[head] ; t != head ; t = R[t]){//找出点最少的一列
            if(S[t] < MX){
                MX = S[t] ;
                c = t ;
            }
        }
        remove(c) ;
        for (int i = D[c] ; i != c ; i = D[i]){
            for (int j = R[i] ; j != i ; j = R[j]){
                remove(C[j]) ;
            }
            if(dfs(k + 1))return 1 ;
            for (int j = L[i] ; j != i ; j = L[j]){
                resume(C[j]) ;
            }
        }
        resume(c) ;
        return 0 ;
    }
    int main() {
        while(cin >> n >> m){
            init() ;
            if(dfs(0))puts("Yes, I found it") ;
            else puts("It is impossible") ;
        }
        return 0 ;
    }
    
  • 相关阅读:
    mac 端口转发方案
    Js 函数
    for 循环语句 与 while 循环
    Javascript 基础2
    Javascript 基础 1
    设计模式学习(一)-概述
    java基础知识-对象和类
    java基础知识-(数组)
    Java面试-框架篇(SSM-SpringMVC)
    Java面试-框架篇(SSM-Mybatis)
  • 原文地址:https://www.cnblogs.com/james1207/p/3324898.html
Copyright © 2011-2022 走看看