POJ 3740
Posted 一个_小菜鸟
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了POJ 3740相关的知识,希望对你有一定的参考价值。
http://poj.org/problem?id=3740
这是一道搜索+回溯的题目,也是我第一次接触到回溯。
题意就是找一些行,这些行可以使每一列都只存在一个1。
深搜加回溯:
memory:118K c++ runtime:674ms。
#include <stdio.h> #include <string.h> #include <iostream> using namespace std; int a[20][305],n,m; bool used[310],fin; bool judge() //判断是否已经寻找到那些行加起来可以使所有的列只存在一个1。 { for(int i=1;i<=m;i++) if(!used[i]) return false; return true; } bool check(int row) //判断当前行是否有与之前行在某一列有冲突(都有1) { for(int i=1;i<=m;i++) if(used[i]&&a[row][i]) return false; // 如果都有1的话,回溯。 for(int i=1;i<=m;i++) if(a[row][i]) used[i]=true; //如果不冲突的话,则把这一行用上,并把其的所有的1所在的行都标记上。 return true; } void dfs(int s) { if(fin||s>n+1) return; //判断退出的标志,即输出的结果,或者行数已经超过了n+1。 if(judge()) { printf("Yes, I found it\n"); fin=true; return; } for(int i=s;i<=n&&!fin;i++) { if(check(i)){ dfs(i+1); for(int j=1;j<=m;j++) //这就是回溯,因为如果I+1与之前的有冲突的话,if(check(i+1))则为false。所以执行的就应该是这一行。 if(a[i][j]) used[j]=false; } } } int main() { while(scanf("%d%d",&n,&m)!=EOF) { memset(a,0,sizeof(a)); for(int i=1;i<=n;i++) for(int j=1;j<=m;j++) scanf("%d",&a[i][j]); fin=false; memset(used,false,sizeof(used)); dfs(1); if(!fin) printf("It is impossible\n"); } return 0; }
以上是关于POJ 3740的主要内容,如果未能解决你的问题,请参考以下文章
[ACM] POJ 3740 Easy Finding (DFS)
poj 3740 Easy Finding(Dancing Links)
POJ_3740 Easy Finding ——精确覆盖问题,DLX模版