DFS(3)

例题1:zjut 1398(全排列)http://acm.zjut.edu.cn/ShowProblem.aspx?ShowID=1398

加入了剪枝,即在全排列中不能输出重复排列,还有就是需要排序

#include<iostream>
#include<string>
#include<cstdio>
#include<algorithm>
using namespace std;
const int MAX=100;
bool visit[MAX];
string s,s1;
string s2="AaBbCcDdEeFfGgHhIiJjKkLlMmNnOoPpQqRrSsTtUuVvWwXxYyZz";
void DFS(int cur) 
{   int len=s.length(); 
    if(cur==len) 
    {  for(int i=0;i<len;i++)
          cout<<s1[i];
       cout<<endl;
    }  
    else   
    for(int i=0;i<len;++i) 
    {  if(!visit[i]) 
       { if(i&&!visit[i-1]&&s[i]==s[i-1]) continue;
         visit[i]=true;
         s1[cur]=s[i];
         DFS(cur+1);  
         visit[i]=false;   
       }    
     }
}
int main()
{   int n;
    cin>>n;
    getchar();
    while(n--)
    { cin>>s;
      for(int i=0;i<s.length();i++)
        for(int j=i+1;j<s.length();j++)
          if(s2.find(s[i])>s2.find(s[j])) swap(s[i],s[j]); //排序 
      DFS(0);
    }
    return 0;
}

这道题做完后可以做POJ 1256了~~

hdu 1241(以前是用BFS做的,现在用DFS做,发现还简单些,呵呵呵~~)题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1241

#include<iostream>
using namespace std;
const int MAX=110;
char map[MAX][MAX];
int dx[8]={0,1,1,1,0,-1,-1,-1};//水平方向的坐标变化 
int dy[8]={-1,-1,0,1,1,1,0,-1};//垂直方向的坐标变化 
int n,m;
int Inside(int x,int y)
{   return x>=0&&x<n&&y>=0&&y<m;
}
void DFS(int x,int y)
{   for(int i=0;i<8;i++)
    {  int Newx=dx[i]+x;
       int Newy=dy[i]+y;
       if(Inside(Newx,Newy)&&map[Newx][Newy]=='@')//要保证在范围内
       { map[Newx][Newy]='*';//要调整过来,搜过了的可以用@外的任意字符代替
         DFS(Newx,Newy);
       }
    }
}
int main()
{   while(cin>>n>>m&&m||n)
    { int step=0;
      for(int i=0;i<n;i++)
       for(int j=0;j<m;j++)
        cin>>map[i][j];
      for(int i=0;i<n;i++)
       for(int j=0;j<m;j++)
        if(map[i][j]=='@')
        { step++;
          DFS(i,j);
        } 
      cout<<step<<endl;
    }
    return 0;
}  

 例题3:nyist 325 (zb的生日)题目链接:http://acm.nyist.net/JudgeOnline/problem.php?pid=325

//abs(a-b)=abs((sum-b)-b)=abs(sum-2*b),所以只需搜其中一个人的即可,用甲乙表示~ 
#include<iostream>
#include<cstdlib>
using namespace std;
int a[25];
int Max,sum; 
void DFS(int cur,int m)//cur是用来保存其中一人的西瓜重量~,用甲表示 
{   if(m<0) return ;
    if(Max>abs(sum-2*cur)) Max=abs(sum-2*cur);
    DFS(cur+a[m],m-1); //甲要a[m]这个西瓜,则甲的西瓜重量+a[m],搜索下一个西瓜。 
    DFS(cur,m-1); //甲不要这个西瓜m则直接搜索下一个西瓜。 
} 
int main()
{   int n;
    while(cin>>n)
    { sum=0;
      Max=1000000000;
      for(int i=0;i<n;i++)
      { cin>>a[i];
        sum+=a[i];
      }
      DFS(0,n-1);
      cout<<Max<<endl;
    }
    return 0;
}


例题4:hdu 1010题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1010

知识点:奇偶剪枝

把矩阵看成如下形式:
0 1 0 1 0 1
1 0 1 0 1 0
0 1 0 1 0 1
1 0 1 0 1 0
0 1 0 1 0 1
从为 0 的格子走一步,必然走向为 1 的格子 。
从为 1 的格子走一步,必然走向为 0 的格子 。
即:
从 0 走向 1 必然是奇数步,从 0 走向 0 必然是偶数步。

所以当遇到从 0 走向 0 但是要求时间是奇数的或者 从 1 走向 0 但是要求时间是偶数的,都可以直接判断不可达!

#include<iostream>
#include<cstring>
using namespace std;
int dx[4]={0,1,0,-1},dy[4]={-1,0,1,0};
char map[7][7];
int M,N,T,flag,ex,ey;
int Inside(int x,int y)
{   return x>=0&&x<N&&y>=0&&y<M;
}
void DFS(int x,int y,int cur)
{   if(x==ex&&y==ey&&cur==T) flag=1;
    if(cur>T||flag) return ; 
    if(T-cur<abs(ex-x)+abs(ey-y)) return ;//剩余时间小于理论值 
    if((T-cur)%2!=(abs(ex-x)+abs(ey-y))%2) return ;//奇偶剪枝!! 
    for(int i=0;i<4;i++)
    {  int Newx=dx[i]+x;
       int Newy=dy[i]+y; 
       if(Inside(Newx,Newy)&&map[Newx][Newy]!='X')
       {  map[Newx][Newy]='X';
          DFS(Newx,Newy,cur+1);
          map[Newx][Newy]='.';//回溯~~~ 
       }
    }   
}
int main()
{   int sx,sy;
    while(cin>>N>>M>>T&&N||M||T)
    { int num=0; 
      for(int i=0;i<N;i++)
        for(int j=0;j<M;j++)
        {  cin>>map[i][j];
           if(map[i][j]!='X') num++;
           if(map[i][j]=='S') sx=i,sy=j;
           if(map[i][j]=='D') ex=i,ey=j;
        } 
      map[sx][sy]='X'; 
      if(num<T) puts("NO");
      else
      { flag=0;
        DFS(sx,sy,0); 
        if(flag) puts("YES");
        else puts("NO");
      }     
    }
    return 0;
}

例题5:hdu 1181题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1181

深度遍历,首字母为b,直到字符串的最后一个字母为m停止,主要是注意输入。。。。得看清楚题目

#include<iostream>
#include<string>
using namespace std;
string s[105],s1;
int num,flag;
bool visit[105];
void DFS(char c)
{    if(c=='m') flag=1;
     if(flag) return ;
     else
     for(int i=0;i<num;i++)
      if(!visit[i]&&s[i][0]==c)
      { visit[i]=true;
        int len=s[i].length();
        DFS(s[i][len-1]);
        visit[i]=false;
      }
}
int main()
{   num=0;
    while(cin>>s1)
    {  s[num++]=s1;  
       if(s1=="0")
       { flag=0;
         for(int i=0;i<num;i++)
         { if(s[i][0]=='b') 
           {  memset(visit,false,sizeof(visit));
              DFS('b'); 
              if(flag) cout<<"Yes."<<endl;              
           }
            if(flag) break;
         }
         if(!flag) cout<<"No."<<endl;
         num=0;//开始看错了题目,输入一直感觉不对劲,原来它是以0作为一组字符串结束,可能还会输入下一组,所以num=0; 
       }
    }
    return 0;
}

 例题6:nyist 82(迷宫寻宝一)题目链接:http://acm.nyist.net/JudgeOnline/problem.php?pid=82

分析:深搜问题,当然可以用广搜,就是要求稍微复杂点,昨天晚上RE了一页,郁闷,直到刚刚才做出来,比方说一个图,每个门的钥匙个数各不相同,我们要开这个门的话就要求找到这个门的所有钥匙,下面的代码中用Key[]保存开每扇门的所需的钥匙数,当然这个不一定需要开所有的门,只要开了某扇门后能够找到出口即可,具体看代码,写的比较的乱~~~

#include<iostream>
#include<cstring>
#include<cstdio>
using namespace std;
const int MAX=25;
#define CLR(arr,val) memset(arr,val,sizeof(arr))
int n,m,flag,Startx,Starty,Endx,Endy;
int visit[5],num[5],Key[5];
int dx[4]={0,1,0,-1},dy[4]={-1,0,1,0};
char map[MAX][MAX];
struct point{
	point(){px=-1;py=-1;}
	point(int x,int y):px(x),py(y){}
    int px,py;
}D[5];
int Inside(int x,int y)
{   return x>=0&&x<n&&y>=0&&y<m;
}
void DFS(int x,int y)
{   if(x==Endx&&y==Endy) flag=1;
    if(flag) return ;
	for(int i=0;i<4;i++)
	{   int Newx=x+dx[i];
	    int Newy=y+dy[i];
        char c=map[Newx][Newy];
		if(c!='X'&&Inside(Newx,Newy))
		{   if(c>='A'&&c<='E')
			{   visit[c-'A']=1;//记录该扇门是否出现过
			    D[c-'A'].px=Newx,D[c-'A'].py=Newy;//记录该扇门的位置
				if(num[c-'A']!=Key[c-'A']) continue ;//若是不满足找到的钥匙的个数等于需要的钥匙数则不进行深搜
			}
			if(c>='a'&&c<='e') 
			{   num[c-'a']++;
			    if(visit[c-'a']&&num[c-'a']==Key[c-'a']) DFS(D[c-'a'].px,D[c-'a'].py);//前提是这扇门已经被访问过
			} 
			map[Newx][Newy]='X';//不需回溯,因为要找钥匙
			DFS(Newx,Newy);
		}
	}
}
int main()
{   int i,j;
	while(cin>>n>>m&&n||m)
	{   flag=0;
        CLR(Key,0);
        CLR(num,0);
		CLR(visit,0);
		for(i=0;i<n;i++)
	        cin>>map[i]; 
	    for(i=0;i<n;i++)
			for(j=0;j<m;j++)
			{  char c=map[i][j];
			   if(c=='S') Startx=i,Starty=j;
			   if(c=='G') Endx=i,Endy=j;
			   if(c>='a'&&c<='e') Key[c-'a']++;
			}
        DFS(Startx,Starty);
		if(flag) cout<<"YES"<<endl;
		else cout<<"NO"<<endl;
	}  
	return 0;
}


 

 


 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 


 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值