【DFS+小操作判重】【HDU2610+HDU2611】Sequence
题意 2610 按照长度优先 位置次之 输出所有不递减序列
2611 按照长度优先 大小次之 输出所有不递减序列
题解不写了 来源于http://www.cnblogs.com/wally/archive/2013/05/12/3074356.html
题目链接:
http://acm.hdu.edu.cn/showproblem.php?pid=2610
http://acm.hdu.edu.cn/showproblem.php?pid=2611、
很好的两道搜索题,都用到了判重。。。orz....不怎么会,看了大牛的解题报告才理解。。。跪神牛
大牛的hdu 2610思路:题意很简单就是在给定的序列中找到固定个数的递增的子序列,如果子序列的总个数少于要求的个数,那么就把所有的子序列输出即可,注意每组测试用例就为有一空行。
#include<iostream> #include<cstdio> #include<cstring> using namespace std; #define MAXN 1010 struct Node{ int num,pos; }path[MAXN]; int num[MAXN]; int n,p,_count,len; bool flag; bool Judge(int st,int ed){ for(int i=st;i<ed;i++){ if(num[i]==num[ed])return false; } return true; } void dfs(int l,int pos){ if(_count>=p)return ; if(l==len){ _count++; flag=true; for(int i=0;i<l-1;i++){ printf("%d ",path[i].num); } printf("%d\n",path[l-1].num); return ; } for(int i=pos;i<n;i++){ if((l!=0&&path[l-1].num<=num[i])||l==0){ if(l!=0&&!Judge(path[l-1].pos+1,i))continue; if(l==0&&!Judge(0,i))continue; path[l].num=num[i]; path[l].pos=i; dfs(l+1,i+1); } } } int main(){ while(~scanf("%d%d",&n,&p)){ for(int i=0;i<n;i++) scanf("%d",&num[i]); _count=0; for(int i=1;i<n;i++){ flag=false; len=i; dfs(0,0); if(_count>=p||(!flag))break; } puts(""); } return 0; }
hdu 2611题目描述:前一题sequence one 属于一类题,都是dfs,首先排一次序,然后再检查时注意输入时的下标,生成的子串不能够出现下标非递增的,也就是首先子串时递增的,其次下标也是递增的,然后不能有重复的子串出现。
技巧:判重的技巧,这里我们可以一开始设置一个flag=false,第一次的时候该flag的为true,然后用一个pre保留当前位置的数,然后后面在搜相同len的序列时,如果当前的数与pre是一样的,说明先前已经搜过了,直接continue就行了,否则,pre就保留这个数,然后搜len+1的数。。。这里的flag和pre用的是太妙了。。。orz...ym!!!
#include<iostream> #include<cstring> #include<cstdio> #include<algorithm> using namespace std; #define MAXN 110 struct Node{ int num,pos; }node[MAXN]; int n,p,len,l,_count; int path[MAXN]; int cmp(const Node &p,const Node &q){ if(p.num!=q.num) return p.num<q.num; return p.pos<q.pos; } bool dfs(int l,int pos,int repos){ if(l==len){ _count++; for(int i=0;i<l-1;i++){ printf("%d ",path[i]); } printf("%d\n",path[l-1]); if(_count==p)return true; return false; } int pre; bool flag=false;//flag和pre的判重妙用,得仔细体会; for(int i=pos;i<=n;i++){ //由于生成的子串是不能出现下标非递增的。 if(node[i].pos>repos){ if(!flag){flag=true;pre=node[i].num;}//判重 else if(pre==node[i].num)continue;//判重 pre=node[i].num;//不相等的话保留当前的数,然后进入下一个dfs继续搜; path[l]=node[i].num; if(dfs(l+1,i+1,node[i].pos))return true; } } return false; } int main(){ while(~scanf("%d%d",&n,&p)){ for(int i=1;i<=n;i++){ scanf("%d",&node[i].num); node[i].pos=i; } sort(node+1,node+n+1,cmp); _count=0; for(int i=1;i<n;i++){ len=i; if(dfs(0,1,0))break; } puts(""); } return 0; }