【POJ3740】Easy Finding,解题报告+思路+代码

原创 2012年03月21日 21:25:00
#include <iostream>
#include <cstring>
#include <cstdlib>
#include <cstdio>
//#define INPUT
/**
    Problem: poj3740 - Easy Finding
    Begin Time:8:30 p.m. 20th/Mar/2012
    End Time: 8:42 p.m. 21st/Mar/2012
    Last Time: Maybe 4hours-;
    Input:
    Standard output:
    Knowledge point:
    DFS+回溯+剪枝
    State: WA x 1 , TLE x 1  -> AC
    Thought:
    --------------------AC后的总结----------------------
    1.定义一个数组selectedCol,表示目前选出了几列中有"1".
    2.在choose之前,要检查selectedRow[i]是否为true.
      如果是true,这行就选过了,就continue
    3.在每次choose某行的时候,都在choose函数里进行check
    if choose_row[i]  == 1 && selectedCol[i] == 1 return false;
    if choose_row[i] && !selectedCol[i] => selectedCol[i] = 1;
    但是在choose之前记得保存selectedCol的状态,以便return false之前进行回溯。
    4.如果choose失败的话,就要检查是否已经找到了全1,如果找到了
        isFound = true;
        在递归函数里检查isFound = true的话就return true;
    5.如果没找到的话,记得回溯。这就要求在递归函数里每次保存selectedCol的状态,失败了进行回溯。
    6.如果leftRow == 0 ,那么就check,如果check,return true;,否则return false;

    剪枝策略:
        每层递归都是从 i = 0 to rowNum 开始选
        如果上层递归选了i,那就下层递归从i+1开始选。
        因为上层递归从0开始选,选到i的话[0,i]的情况已经由上层递归选完了。
        而且行数跟顺序无关
        比如说
        第一层递归选了1
        那么第二,第三……一直到最后一层递归,肯定是把第一次选1的所有情况都遍历了,
        第一层递归才能去选2
        而且
        1   2   3   4   5   6
        和
        6   5   4   3   2   1
        这么选择是没有区别的,所以下一层递归从ind+1开始就可以了
        加上这个剪枝,653ms就过了。
    更变态的思路:
        由于是0,1我们可以按位表示嘛!然后按照规则算,应该会非常快~
    递归函数定义:
    f(int totalRow,int totalCol,int leftRow,int ind);
    totalRow表示总共有多少行
    totalCol表示列数
    leftRow表示还有几行没选
    int ind表示从现在第几行开始选。
    --------------------AC前的涂鸦----------------------
    其实这道题跟STICK是差不多的,当然,状态压缩是必须的。
    每行压缩成一个数字,然后是否有几个数字相加起来正好等于
    1111111....
    注意,最多可以有10^300,所以这个比较囧!

    每一个状态就是按行i是否被选择来决定,
    选择了某一行之后,就定义tmp[m]对应的列已经被占领。
    那么剩下的就转化为用leftNum - 1行来拼出来其他的列了,如果都能拼出来,那么
    return true,否则return false;
    定义函数f(rowNum,colNum,leftNum);表示总共有rowNum列,有colNum行,剩leftNum没有选
    每次选择的时候定义一个check,看看是否已经选出了每列全有1的行。
    还有一个check2,看看当前选的行是否跟以前的行有冲突。
**/
using namespace std;

int matrix[20][310]; ///开大一点总是没错的
bool selectedCol[310];
bool selectedRow[18];
bool isFound;
bool checked(const int colNum)
{
    for(int i = 0 ; i < colNum ; i++)
    {
        if (!selectedCol[i])
            return false;
    }
    return true;
}
bool choose(const int a[310],int colNum)
{
    int tmp_state[310];
    memset(tmp_state,0,sizeof(tmp_state));
    memcpy(tmp_state,selectedCol,sizeof(tmp_state));
    for(int i = 0 ; i < colNum ; i++)
    {
        if(!selectedCol[i] && a[i] )
        {
            selectedCol[i] = a[i];
        }
        else
        {
            if ( selectedCol[i] && a[i] )
            {
                memcpy(selectedCol,tmp_state,sizeof(tmp_state));
                return false;
            }
        }
    }
    return true;
}
bool Solve(int rowNum,int colNum,int leftNum,int ind)
{
    int tmp_state[310];
    memset(tmp_state,0,sizeof(tmp_state));
    if( isFound )
        return true;
    if (leftNum == 0)
    {
        if ( checked(colNum) )
        {
            isFound = true;
            return true;
        }
        else
        {
            return false;
        }
    }
    for(int i = ind ; i < rowNum ; i++)
    {
        memcpy(tmp_state,selectedCol,sizeof(tmp_state));
        if( isFound ) return true;
        if ( selectedRow[i] ) continue;
        if ( choose(matrix[i],colNum) )
        {
            if( selectedRow[i] != true && !checked(colNum) )
            {
                selectedRow[i] = true;
                Solve(rowNum,colNum,leftNum - 1,i+1);
            }
            else
            {
                if ( checked(colNum) )
                {
                 isFound = true;
                 return true;
                }
            }
       //     memcpy(matrix[i],tmp_state,sizeof(tmp_state));
            memcpy(selectedCol,tmp_state,sizeof(selectedCol));
            selectedRow[i] = false;
        }
      //  selectedRow[i] = false;
    }
    return false;
}
int main()
{
    int n,m;
#ifdef INPUT
    freopen("b:\\acm\\poj3740\\input.txt","r",stdin);
#endif
    while(scanf("%d%d",&m,&n) != EOF )
    {
        isFound = false;
        memset(matrix,0,sizeof(matrix));
        memset(selectedCol,0,sizeof(selectedCol));
        memset(selectedRow,0,sizeof(selectedRow));
        for(int i = 0 ; i < m ; i++)
        {
            for(int j = 0 ; j < n ; j++)
            {
                scanf("%d",&matrix[i][j]);
            }
        }
        if ( Solve(m,n,m,0) )
        {
            printf("Yes, I found it\n");
        }
        else
        {
            printf("It is impossible\n");
        }
    }
    return 0;
}

相关文章推荐

【POJ2255】Tree Recovery解题报告 思路 + 数据 +代码

#include #include #include #include using namespace std; /* Author: YuXun Lu Time:23rd/2...

【POJ1077】Eight 八数码问题,解题报告+思路+代码

#include #include #include #define INPUT using namespace std; /** Problem : poj1077,hdu1043...

【POJ2488】 A knight's Journey 解题报告 测试数据+代码+思路

#include #include #include #include #include //#define INPUT //#define DBG /** Problem:POJ2...

【POJ1011 Sticks】解题报告+思路+代码

#include #include #include #include #include //#define INPUT using namespace std; /** Probl...

【POJ1182】食物链,思路+数据+代码,可能是史上关于这道题最详细的解题报告

#include #include #include #include //#define INPUT /** Problem:1182 - 食物链,NOI2001 Begin...
  • c0de4fun
  • c0de4fun
  • 2012年03月04日 19:54
  • 18349

【poj1164】The Castle,解题报告+思路+代码+数据

#include #include #include #include #include #include #define INPUT using namespace std; /** ...

POJ 3740 Easy Finding 位运算压缩+DFS or Dancing Links

Easy Finding 这道题运用二进制DFS是比较好的方法,当然还可以用dancing links,这个比较高级,先把我看别人的二进制思路然后写的代码贴上来。 当然本题是体现不出DLX的高级之...

【POJ3740】Easy Finding DLX(Dancing Links)精确覆盖问题

Dancing Links(DLX)的个人心得。
  • Vmurder
  • Vmurder
  • 2014年10月29日 15:11
  • 1366

【POJ】3740 Easy Finding 精确覆盖入门题

传送门:【POJ】3740 Easy Finding 题目分析:

poj 3740 Easy Finding

题意:给一个01矩阵,问是否能找到一个行的集合,使得集合中每列出现且仅出现一次‘1’。         思路:舞蹈链X算法模版题。来谈谈我对这个算法的理解。。这个算法是一个深搜,但是它的数据结构非常...
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:【POJ3740】Easy Finding,解题报告+思路+代码
举报原因:
原因补充:

(最多只允许输入30个字)