首页 > 代码库 > [ACM] POJ 3740 Easy Finding (DFS)

[ACM] POJ 3740 Easy Finding (DFS)

Easy Finding
Time Limit: 1000MS Memory Limit: 65536K
Total Submissions: 16482 Accepted: 4476

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

Source

POJ Monthly Contest - 2009.08.23, MasterLuo

 

解题思路:

题意为给出n*m的01矩阵,问能不能从中选出一些行,使得这些行组成的新矩阵中,每列有且只有一个1.

本题用Dlx可解,明显的完全覆盖问题。这里练习DFs,用DFS按照行号递增的顺序枚举行就可以.一开始犯了一个很严重的错误,就是没有按行号递增的顺序,导致了重复,其实 1 2 5和 5 1 2其实是一样的,所以DFS(int row), 参数是行号,下一层递归为DFs(row+1), 每次进入DFs都要首先判断是否符合题意,即新矩阵每列有且只有一个1,用vis[j]数组表示新矩阵中第j列是否已经有一个1,如果满足该条件,就不用往下继续递归了,直接标记成功,return即可。

通过这道题,加深了对递归的理解,感觉只要想明白,递归也不是那么难理解。

假设当n=4时,搜索的行号是按这样的顺序:

1
1 2
1 2 3
1 2 3 4
1 2 4
1 3
1 3 4
1 4
2
2 3
2 3 4
2 4
3
3 4
4

代码:

#include <iostream>
#include <stdio.h>
#include <algorithm>
#include <string.h>
#include <stdlib.h>
#include <cmath>
#include <iomanip>
#include <vector>
#include <set>
#include <map>
#include <stack>
#include <queue>
#include <cctype>
using namespace std;
#define ll long long
const int maxn=18;
const int maxm=302;
int mp[maxn][maxm];
int n,m;
bool vis[maxm];// vis[i]表示第i列是否有一个1了
bool ok;
int hash[maxn];//第i行有多少个1

bool yes(int row)//判断第row行可不可行
{
    for(int i=1;i<=m;i++)
        if(mp[row][i]&&vis[i])
        return false;
    return true;
}

void DFS(int cnt,int row)//参数cnt为当前所选的行里面列已经有多少个1,row是当前选择的第几行
{
    if(cnt==m||(row>n&&cnt==m))///这里也要注意,当选择的行号大于n时,也要判断已选择的行号是否满足题意
    {
        ok=1;
        return;
    }
    if(row>n)
        return;
    for(int i=row;i<=n;i++)///所犯的一个很严重的错误,一开始写成i=1了,重复了,行号是按照递增的顺序来选择的,1 5 8和5 1 8是同一种情况
    {
        if(yes(i))
        {
            for(int j=1;j<=m;j++)
            {
                if(mp[i][j])
                    vis[j]=1;
            }
            DFS(cnt+hash[i],i+1);
            if(ok)
                break;
            for(int j=1;j<=m;j++)
            {
                if(mp[i][j])
                    vis[j]=0;
            }
        }
    }
}

int main()
{
    while(scanf("%d%d",&n,&m)!=EOF)
    {
        memset(hash,0,sizeof(hash));
        for(int i=1;i<=n;i++)
            for(int j=1;j<=m;j++)
        {
            scanf("%d",&mp[i][j]);
            if(mp[i][j])
                hash[i]++;
        }
        ok=0;
        memset(vis,0,sizeof(vis));
        DFS(0,1);
        if(ok)
            printf("Yes, I found it\n");
        else
            printf("It is impossible\n");

    }
    return 0;
}


 

 

[ACM] POJ 3740 Easy Finding (DFS)