POJ-3740-Easy Finding【DLX精确覆盖】

POJ-3740-Easy Finding

                    Time Limit: 1000MS      Memory Limit: 65536K

Description

Given a M×N matrix A. Aij ∈ {0, 1} (0 ≤ i < M, 0 ≤ j < N), could you find some rows that let every cloumn contains and only contains one 1.

Input

There are multiple cases ended by EOF. Test case up to 500.The first line of input is M, N (M ≤ 16, N ≤ 300). The next M lines every line contains N integers separated by space.

Output

For each test case, if you could find it output “Yes, I found it”, otherwise output “It is impossible” per line.

Sample Input
3 3
0 1 0
0 0 1
1 0 0
4 4
0 0 0 1
1 0 0 0
1 1 0 1
0 1 0 0

Sample Output
Yes, I found it
It is impossible

题目链接:POJ-3740

题目大意:已知一个row*col的01矩阵,问能否找出某些行,使得所有的列都有且只有一个1。

题目思路:为了试试这个模板去找的题。直接套就可以了。

以下是代码:

#include <stdio.h>
#include <string.h>
#include <iostream>
#include <algorithm>
#include <vector>
#include <queue>
#include <set>
#include <map>
#include <string>
#include <math.h>
#include <stdlib.h>
#include <time.h>
using namespace std;
const int maxnode = 500010;
const int MaxM = 1010;
const int MaxN = 510;
struct DLX
{
    int n,m,size;
    int U[maxnode],D[maxnode],R[maxnode],L[maxnode],Row[maxnode],Col[maxnode];
    int H[MaxN],S[MaxM];
    int ansd;
    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;
        }
    }
    //这里的remove其实并没有真正删除掉结点,可以用resume恢复
    void remove(int c)  //删除第c列上的元素所在行 
    {
        L[R[c]] = L[c]; R[L[c]] = R[c];
        //删除c,c是列指针,删除了c就代表删除了整列,因为递归后不可能访问到c了 
        for(int i = D[c];i != c;i = D[i]) //c所在列上的元素i 
            for(int j = R[i];j != i;j = R[j]) //i和j一行的,删掉j 
            {
                U[D[j]] = U[j];
                D[U[j]] = D[j];
                --S[Col[j]]; //j所在列的元素(‘1’的个数)-1;
            }
    }
    void 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;
    }
    void Dance(int d)
    {
         //剪枝下
        if(ansd != -1 && ansd <= d)return;
        if(R[0] == 0)
        {
            if(ansd == -1)ansd = d;
            else if(d < ansd)ansd = d;
            return;
        }
        int c = R[0];
        for(int i = R[0];i != 0;i = R[i]) if(S[i] < S[c]) c = i;  //找元素最少的列c,一种优化 
        remove(c); //删除列c 
        for(int i = D[c];i != c;i = D[i])
        {
            for(int j = R[i];j != i;j = R[j])remove(Col[j]);  //删除所有可能的冲突元素 
             Dance(d+1);
            for(int j = L[i];j != i;j = L[j])resume(Col[j]);
        }
        resume(c);
    }
};

DLX g;

int main()
{
    int n,m;
    while(cin >> n >> m)
    {
        g.init(n,m);  //初始化 
        for (int i = 1; i <= n; i++)
        {
            for (int j = 1; j <= m; j++)
            {
                int x;
                cin >> x;
                if (x) g.Link(i,j);  //存入为1的地方 
            }
        } 
        g.ansd = -1;  //记录答案 
        g.Dance(0);
        if (g.ansd > 0) puts("Yes, I found it");  
        else puts("It is impossible");  
    }
}

你可能感兴趣的:(poj,3740,DLX精确覆盖)