标签:dfs
| Time Limit: 1000MS | Memory Limit: 65536K | |
| Total Submissions: 16482 | Accepted: 4476 |
Description
Input
Output
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
解题思路:
题意为给出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)
标签:dfs
原文地址:http://blog.csdn.net/sr_19930829/article/details/42706227