*********深度优先搜索**********

 

目录

DFS算法:

在图上寻找路径1.判断从v出发是否能到终点 

2.判断从v出发是否能到终点,如果能,记录路径

3.在图上寻找最优(步数最少)路径

4.遍历图上所有的节点

2815:城堡问题

 4103:踩方格


DFS算法:

思想:一直往深处走,直到找到解或者走不下去为止

大体框架:

DFS(dep,.......)

{

    if(找到解 || 走不下去)

    {

         .........

        return ;

     }

    枚举下一种情况,DFS(dep+1,........)

}

 

参考文献::

BFS与DFS的区别

在图上寻找路径
1.判断从v出发是否能到终点 

bool DFS(v)
{
   if(v 为终点)
     return true;
   if(v 为旧点)
     return false;
   //以上两种情况都不符合
   //将v标记为旧点
   再对与v相邻的每一个节点U再去搜索{
    if(DFS(U)==true)
      return true;
    }
    return false;    
} 
int main()
{
    //将所有的点都标记为新点
   //起点 = 1
   //终点 = 8
   cout<<DFS(起点)<<endl; 
   return 0;
}

2.判断从v出发是否能到终点,如果能,记录路径
 

Node path[MAX_LEN];
int depth;
bool DFS(v)
{
   if(v为终点)
   {
         path[depth]=v;
      return true;  
   }
   if(v为旧点)
      return false;
   将v标记为旧点;
   path[depth++]=v;
   对和v相邻的每个节点U{
      if(DFS(U)==true)
         return true;
   } 
   depth--;
   return false;
      
} 
int main()
{
   //将所有的点都标记为新点
   depth=0;
   if(DFS(起点))
   {
       for(int i=0;i<depth;i++)
       {
          cout<<path[i]<<" ";    
    }
   } 
return 0;
} 

3.在图上寻找最优(步数最少)路径
 

Node bestPath[MAX_LEN];
int minSteps=INF;//最优路径数,初值设置为最大
Node path[MAX_LEN];//记录路径
int depth;
void DFS(v)
{
    if(v为终点)
    {
        path[depth]=v;
        if(depth<minSteps) //记录下最少的步数,最优的路径 
        {
            minSteps=depth;
        拷贝path到bestPath; 
        }
        return ;
    }
    if(v为旧点)  
        return ;
    if(depth >= minSteps)//剪枝   
        return ;
    将v标记为旧点;
    path[depth]=v;
    depth++;
    对和v相邻的每个节点U{
        DFS(U);
    } 
    depth--;
    将v恢复为新点 
}
int main()
{
    将所有点都标记为新点;
    depth=0;
    DFS(起点);
    if(minSteps !=  INF)
    {
       for(int i=0;i<=minSteps;i++)
       {
          cout<<bestPath[i]<<endl;       
       }    
    } 
    return 0;
}

4.遍历图上所有的节点
 

void DFS(v)
{
    if(v是旧点)
      return ;
    将v标记为旧点
    对和v相邻的每个点U
    {
        DFS(U);    
    }    
}
int main()
{
    将所有的点都标记为新点;
    while(在图中能找到的新点K)
    {
        DFS(K);
    } 
}

2815:城堡问题

描述

     1   2   3   4   5   6   7  
   #############################
 1 #   |   #   |   #   |   |   #
   #####---#####---#---#####---#
 2 #   #   |   #   #   #   #   #
   #---#####---#####---#####---#
 3 #   |   |   #   #   #   #   #
   #---#########---#####---#---#
 4 #   #   |   |   |   |   #   #
   #############################
           (图 1)

   #  = Wall   
   |  = No wall
   -  = No wall


图1是一个城堡的地形图。请你编写一个程序,计算城堡一共有多少房间,最大的房间有多大。城堡被分割成mn(m≤50,n≤50)个方块,每个方块可以有0~4面墙。

输入

程序从标准输入设备读入数据。第一行是两个整数,分别是南北向、东西向的方块数。在接下来的输入行里,每个方块用一个数字(0≤p≤50)描述。用一个数字表示方块周围的墙,1表示西墙,2表示北墙,4表示东墙,8表示南墙。每个方块用代表其周围墙的数字之和表示。城堡的内墙被计算两次,方块(1,1)的南墙同时也是方块(2,1)的北墙。输入的数据保证城堡至少有两个房间。

输出

城堡的房间数、城堡中最大房间所包括的方块数。结果显示在标准输出设备上。

样例输入

4 
7 
11 6 11 6 3 10 6 
7 9 6 13 5 15 5 
1 10 12 7 13 7 5 
13 11 10 8 10 12 13 

样例输出

5
9

来源

1164

计算连通分量并且输出这些连通分量中数量的最大数值。

#include<stdio.h>
#include<stdlib.h>
#include<iostream>
#include<algorithm>
#include<string.h>
#include<queue>
using namespace std;
const int maxn=60;
int visisted[maxn][maxn];
int g[maxn][maxn];
int roomNums=0,roomArea,maxnArea=0;
int n,m;
void dfs(int i,int j)
{
	roomArea++;
	visisted[i][j]=1;
	//cout<<"****"<<endl;
	if((g[i][j]&1)==0 && !visisted[i][j-1])
	   dfs(i,j-1);
	if((g[i][j]&2)==0 && !visisted[i-1][j])
	    dfs(i-1,j);
	if((g[i][j]&4)==0 && !visisted[i][j+1])
	    dfs(i,j+1);
	if((g[i][j]&8)==0 && !visisted[i+1][j])
	    dfs(i+1,j);
//g[x][y] & 4与(g[x][y] & 4 )值不同  &优先级很低 所以(g[x][y] & 4 == 0)不对 这样应该等价于 4==0 然后再计算
}
int main()
{
	//freopen("in.txt","r",stdin);
	scanf("%d%d",&n,&m);
     for(int i=0;i<n;i++)
     {
     	for(int j=0;j<m;j++)
     	{
     	   scanf("%d",&g[i][j]);
		}
	 }
	 memset(visisted,0,sizeof(visisted));
	 roomNums=0;
	 for(int i=0;i<n;i++)
	 {
	 	for(int j=0;j<m;j++)
	 	{
	 	   if(visisted[i][j]==0)
			{
		        roomArea=0;
				roomNums++;
				dfs(i,j);
				//cout<<"roomArea"<<roomArea<<endl;
				maxnArea=max(roomArea,maxnArea);
			}	
		}
	 }
	 printf("%d\n%d\n",roomNums,maxnArea);
	 return 0;
}

注意:

1.在dfs里,判断当前的点能够往哪个方向走的时候,要与1 2 4 8分别做判断,能往哪个方向走,就往哪个方向走,

 4103:踩方格

描述

有一个方格矩阵,矩阵边界在无穷远处。我们做如下假设:
a.    每走一步时,只能从当前方格移动一格,走到某个相邻的方格上;
b.    走过的格子立即塌陷无法再走第二次;
c.    只能向北、东、西三个方向走;
请问:如果允许在方格矩阵上走n步,共有多少种不同的方案。2种走法只要有一步不一样,即被认为是不同的方案。

输入

允许在方格上行走的步数n(n <= 20)

输出

计算出的方案数量

样例输入

2

样例输出

7

往北走:

#include<stdio.h>
#include<stdlib.h>
#include<iostream>
#include<algorithm>
#include<string.h>
#include<queue>
using namespace std;
int vis[100][100];
int dfs(int i,int j,int n)
{
	if(n==0)
	{
		return 1;
	}
	vis[i][j]=1;
	 int num=0;
	if(vis[i-1][j]==0)
	 num+=dfs(i-1,j,n-1);
	if(vis[i][j+1]==0)
	 num+=dfs(i,j-1,n-1);
	if(vis[i][j-1]==0)
	 num+=dfs(i,j-1,n-1);
	 vis[i][j]=0;
	 return num;
}
int main()
{
	int n;
	cin>>n;
	memset(vis,0,sizeof(vis));
	cout<<dfs(20,25,n)<<endl;
	return 0;
}

注意:

1.起始步数最少是20,n<=20,所以起始位置最少是20,从0开始的,还往北走,就会出错。北面不能走,是墙 。

往南走:

#include<stdio.h>
#include<stdlib.h>
#include<iostream>
#include<algorithm>
#include<string.h>
#include<queue>
using namespace std;
int vis[100][100];
int dfs(int i,int j,int n)
{
	if(n==0)
	{
		return 1;
	}
	vis[i][j]=1;
	 int num=0;
	if(vis[i+1][j]==0)
	 num+=dfs(i+1,j,n-1);
	if(vis[i][j+1]==0)
	 num+=dfs(i,j-1,n-1);
	if(vis[i][j-1]==0)
	 num+=dfs(i,j-1,n-1);
	 vis[i][j]=0;
	 return num;
}
int main()
{
	int n;
	cin>>n;
	memset(vis,0,sizeof(vis));
	cout<<dfs(0,25,n)<<endl;
	return 0;
}

注意:

1. 从0开始走就可以。

 POJ 1724 ROADS

 

Description

N cities named with numbers 1 ... N are connected with one-way roads. Each road has two parameters associated with it : the road length and the toll that needs to be paid for the road (expressed in the number of coins). 
Bob and Alice used to live in the city 1. After noticing that Alice was cheating in the card game they liked to play, Bob broke up with her and decided to move away - to the city N. He wants to get there as quickly as possible, but he is short on cash. 

We want to help Bob to find the shortest path from the city 1 to the city N that he can afford with the amount of money he has. 

Input

The first line of the input contains the integer K, 0 <= K <= 10000, maximum number of coins that Bob can spend on his way. 
The second line contains the integer N, 2 <= N <= 100, the total number of cities. 

The third line contains the integer R, 1 <= R <= 10000, the total number of roads. 

Each of the following R lines describes one road by specifying integers S, D, L and T separated by single blank characters : 

  • S is the source city, 1 <= S <= N 
  • D is the destination city, 1 <= D <= N 
  • L is the road length, 1 <= L <= 100 
  • T is the toll (expressed in the number of coins), 0 <= T <=100


Notice that different roads may have the same source and destination cities.

Output

The first and the only line of the output should contain the total length of the shortest path from the city 1 to the city N whose total toll is less than or equal K coins. 
If such path does not exist, only number -1 should be written to the output. 

Sample Input

5
6
7
1 2 2 3
2 4 3 3
3 4 2 4
1 3 4 1
4 6 2 1
3 5 2 0
5 4 3 2

Sample Output

11

Source

CEOI 1998

N个城市,编号 1到N。城市间有 R条单向道路。
每条道路连接两个城市,有长度和过费属性。
Bob 只有 K块钱,他想从城市 1走到城市 N。问最短共需要走多长的路如果到不了 N,输 出-1。

 

#include<stdio.h>
#include<stdlib.h>
#include<iostream>
#include<algorithm>
#include<string.h>
#include<queue>
using namespace std;
int k,n,r;
struct Road
{
	int d,l,t;
};
vector<vector<Road> >cityMap(110);
//二维数组,每一个cityMap里面元素又相当于是一个vector<Road>数组 
int minLen=1<<30;
int totalLen;
int totalCost;
int visited[110];
int minL[110][10100];
void dfs(int s)
{
	if(s==n)
	{
		minLen=min(minLen,totalLen);
		return ;
	}
	for(int i=0;i<cityMap[s].size();++i)
	{
		int d=cityMap[s][i].d;
		if(!visited[d])
		{
			int cost=totalCost+cityMap[s][i].t; 
			if(cost>k)
			   continue;
			if(totalLen+cityMap[s][i].l>=minLen || totalLen+cityMap[s][i].l>=minL[d][cost])
			continue;
			totalLen+=cityMap[s][i].l;
			totalCost+=cityMap[s][i].t;
			minL[d][cost]=totalLen;
			visited[d]=1;
			dfs(d);
			visited[d]=0;
			totalCost-=cityMap[s][i].t;
			totalLen-=cityMap[s][i].l;
		}
	}
}
int main()
{
	cin>>k>>n>>r;
	for(int i=0;i<r;i++)
	{
		int s;
		Road r;
		cin>>s>>r.d>>r.l>>r.t;
		if(s!=r.d)
		cityMap[s].push_back(r);
	}
	//cout<<"******"<<endl;
	for(int i=0;i<110;++i)
	{
	  for(int j=0;j<10100;++j)	
	  {
	  	minL[i][j]=1<<30;
	  	//cout<<"****"<<endl;
	  }
	}
	//cout<<"pppppp"<<endl;
	memset(visited,0,sizeof(visited));
	totalLen=0;
	totalCost=0;
	visited[1]=1;
	minLen=1<<30;
	//cout<<"*******"<<endl;
	dfs(1);
	if(minLen<(1<<30))
	  cout<<minLen<<endl;
	else
	  cout<<"-1"<<endl;
}
#include<stdio.h>
#include<stdlib.h>
#include<iostream>
#include<algorithm>
#include<string.h>
#include<queue>
using namespace std;
#define INF 0x3f3f3f3f
int k,n,r;
int u,v,w,e;
struct Node
{
	int d,l,t;
};
int vis[1100];
vector<Node>G[1100];
int minlen=INF;
int minL[1100][10100];
void dfs(int s,int money,int len)
{
	if(s==n)
	{
		minlen=min(minlen,len);//找最短路径长度  是min 我已开始写成max  改了好久
		return ;
	}
	for(int i=G[s].size()-1;i>=0;i--)//以s为起点,再找其他的点(s的邻接点)
	{
		if(!vis[G[s][i].d] && money>=G[s][i].t)//如果没有被访问过并且当前的钱能够走到那个邻接点
		{
			if(minL[G[s][i].d][money-G[s][i].t]<=len+G[s][i].l || len+G[s][i].l>minlen)//如果走到这个城市,并且花了一定钱的情况下的长度,长度小于不走时的长度或者长度太大
			  continue;//就不走
			minL[G[s][i].d][money-G[s][i].t]=len+G[s][i].l;//更新
			dfs(G[s][i].d,money-G[s][i].t,len+G[s][i].l);
			vis[G[s][i].d]=0;//恢复
		}
	}
}
int main()
{
	cin>>k>>n>>r;
	for(int i=0;i<r;i++)
	{
		scanf("%d%d%d%d",&u,&v,&w,&e);
		Node t;
		t.d=v;
		t.l=w;
		t.t=e;
        if(u!=v) //特别注意这一句判断语句  
		G[u].push_back(t);
	}
	memset(vis,0,sizeof(vis));
	memset(minL,0x3f,sizeof(minL));
	vis[1]=1;
	dfs(1,k,0);
	if(minlen==INF)
	{
		puts("-1");
	}
	else
	{
		cout<<minlen<<endl;
	}
	return 0;
}

注意:

1.找最小的路径长度,所以是  min ,错写成max 。

2.判断条件要写全。

 

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值