精华内容
下载资源
问答
  • DFS算法分析

    千次阅读 2017-11-29 21:17:30
    深度优先算法与广度优先算法可谓是图论中的两个基础算法。本科时候被这两个算法折磨的也是很惨。今天来分析一下DFS的过程。
    
    

    深度优先算法与广度优先算法可谓是图论中的两个基础算法。本科时候被这两个算法折磨的也是很惨。今天来分析一下DFS的过程。

    首先我们介绍一下图的表示方式。图是由一组顶点和一组能够将两个顶点相连的边组成的。

    我们可以用邻接矩阵,边的数组和邻接表数组三种方式来表示图。这里我们使用邻接表的形式,使用一个以顶点为索引的列表数组,其中的每个元素都是和该顶点相邻的顶点列表。

    邻接表的数据结构如下所示:

    public class Graph {
    	private final int V;	//顶点数目
    	int E;
    	private List<Integer>[] adj;	//邻接表
    
    	public Graph(int V) {
    		this.V=V;
    		this.E=0;
    		adj=new ArrayList[V];		//创建邻接表
    		for(int v=0;v<V;v++)		//将所有链表初始化为空
    			adj[v]=new ArrayList<>();
    	}
    
    	void addEdge(int v, int w) {
    		adj[v].add(w);
    		adj[w].add(v);
    		E++;
    	} // 向图中添加一条边v-w
    
    	Iterable<Integer> adj(int v) {
    		return adj[v];
    	} // 和v相邻的所有顶点
    
    	public static int degree(Graph G, int v) {
    		int degree = 0;
    		for (int w : G.adj(v))
    			degree++;
    		return degree;
    	}
    }

    其中,主要的数据结构为List<Integer>[] adj邻接表数组,它是一个链表数组,每当插入一条边时,再相应的链表中加入对应的节点。


    图的很多性质和路径有关,因此一种很自然的想法是沿着图的边从一个顶点移动到另一个顶点。

    走迷宫:

    思考图的搜索过程的一种有益的方法是,考虑另一个和它等价但历史悠久而又特别的问题——在一个由各种通道和路口组成的迷宫中找到出路。用迷宫代替图,通道代替边,路口代替顶点。一种古老的方法叫做Tremaux搜索:要探索迷宫中的所有通道,我们需要:

    选择一条没有标记过的通道,在你走过的路上铺一条绳子;

    标记所有你第一次路过的路口和通道;

    当来到一个标记过的路口时(用绳子)回退到上个路口;

    当回退到的路口已经没有可走的通道时继续回退。

    绳子可以保证你总能找到一条出路,标记则能保证你不会两次经过同一条通道或者同一个路口。我们来看看图的搜索算法。

    public class DepthFirstSearch {
    	private boolean[] marked;
    	private int count;
    
    	public DepthFirstSearch(Graph G, int s) {
    		marked = new boolean[G.V()];
    		dfs(G, s);
    	}
    
    	public void dfs(Graph G, int v) {
    		marked[v] = true;
    		count++;
    		for (int w : G.adj(v))
    			if (!marked[w])
    				dfs(G, w);
    	}
    
    	public boolean marked(int w){
    		return marked[w];
    	}
    	
    	public int count(){
    		return count;
    	}
    }
    搜索连通图的经典递归算法(遍历所有的顶点的和边)和Tremaus搜索类似,但描述起来更简单。要搜索一幅图,只需用一个递归方法来遍历所有顶点。在访问其中一个顶点时:

    将它标记为已访问;

    递归的访问它的所有没有被标记过的邻居顶点。

    这种方法称为深度优先搜索(DFS)。它使用一个boolean数组来记录和起点连通的所有顶点。递归方法会标记给定的顶点并调用自己来访问该顶点的相邻列表中所有没有被标记过的顶点。

    代码方法的调用和返回机制对应迷宫中绳子的作用:当已经处理过依附于一个顶点的所有边时(搜索了路口连接的所有通道),我们只能“返回”(return)。在图中我们会经过每条边两次(在它的两个端点各一次)。

    在无向图的深度优先搜索中,在碰到边v-w时,要么进行递归调用(w没有被标记过),要么跳过这条边(w已经被标记过)。第二次从另一个方向w-v遇到这条边时,总是会忽略它,因为它的另一端v肯定已经被访问过了。


    dfs寻找路径

    单点路径问题在图的处理领域十分重要。Paths类构造函数Paths(Graph G,int s)在G中找出所有起点为s的路径。

    下面的算法基于dfs实现Path。在dfs中增加了一个实例变量edgeTo[]整型数组来起到Tremaux搜索中绳子的作用。这个数组可以找到从每个与s连通的顶点回到s的路径。它会记住每个顶点到起点的路径,而不是记录当前顶点到起点的路径。为了做到这一点,在由边v-w第一次访问任意w时,将edgeTo[w]设为v来记住这条路径。换句话说,v-w是从s到w的路径上最后一条已知的边。这样,搜索的结果是一颗以起点为根结点的树,edgeTo[]是一颗由父链接表示的树。

    public class DepthFirstPaths {
    	private boolean[] marked;	//这个顶点上调用过dfs()了吗?
    	private int[] edgeTo;		//从起点刀一个顶点的已知路径上的最后一个顶点
    	private final int s;		//起点
    	public DepthFirstPaths(Graph G,int s) {
    		marked=new boolean[G.V()];
    		edgeTo=new int[G.V()];
    		this.s=s;
    		dfs(G,s);
    	}
    
    	private void dfs(Graph G,int v){
    		marked[v]=true;
    		for(int w:G.adj(v))
    			if(!marked[w]){
    				edgeTo[w]=v;
    				dfs(G, w);
    			}
    	}
    	
    	public boolean hasPathTo(int v){
    		return marked[v];
    	}
    	
    	public Iterable<Integer> pathTo(int v){
    		if(!hasPathTo(v)) return null;
    		Stack<Integer> path=new Stack<>();
    		for(int x=v;x!=s;x=edgeTo[x])
    			path.push(x);
    		path.push(s);
    		return path;
    	}
    }
    

    dfs另一个应用是找出一幅图的所有连通分量。它能够将所有顶点切分为等价类(连通分量)。

    用例可以用id()方法将连通分量用数组保存,使用了一个Bag对象数组。

    CC的实现使用了marked[]数组来寻找一个顶点作为每个连通分量中深度优先搜索的起点。递归的深度优先搜索第一次调用的参数世顶点0——它回标记所有与0连通的顶点。然后构造函数中的for循环回查找每个没有被标记的顶点并递归调用dfs()来标记和它相邻的所有顶点。

    public class CC {
    	private boolean[] marked;
    	private int[] id;
    	private int count;
    	
    	public CC(Graph G) {
    		marked=new boolean[G.V()];
    		id=new int[G.V()];
    		for(int s=0;s<G.V();s++)
    			if(!marked[s]){
    				dfs(G,s);
    				count++;
    			}
    	}
    	
    	private void dfs(Graph G,int v){
    		marked[v]=true;
    		id[v]=count;
    		for(int w:G.adj(v))
    			if(!marked[w])
    				dfs(G,w);
    	}
    	
    	public boolean connected(int v,int w){
    		return id[v]==id[w];
    	}
    	
    	public int id(int v){
    		return id[v];
    	}
    	
    	public int count(){
    		return count;
    	}
    }
    

    dfs应用:判断G是无环图么?

    public class Cycle {
    	private boolean[] marked;
    	private boolean hasCycle;
    
    	public Cycle(Graph G) {
    		marked = new boolean[G.V()];
    		for (int s = 0; s < G.V(); s++)
    			if (!marked[s])
    				dfs(G, s, s);
    	}
    
    	private void dfs(Graph G, int v, int u) {
    		marked[v] = true;
    		for (int w : G.adj(v))
    			if (!marked[w])
    				dfs(G, w, v);
    			else if (w != u)
    				hasCycle = true;
    	}
    
    	public boolean hasCycle() {
    		return hasCycle;
    	}
    
    }
    

    dfs应用:G是二分图么?

    public class TwoColor {
    	private boolean[] marked;
    	private boolean[] color;
    	private boolean isTwoColorable = true;
    
    	public TwoColor(Graph G) {
    		marked = new boolean[G.V()];
    		color = new boolean[G.V()];
    		for (int s = 0; s < G.V(); s++)
    			if (!marked[s])
    				dfs(G, s);
    	}
    
    	private void dfs(Graph G, int v) {
    		marked[v] = true;
    		for (int w : G.adj(v))
    			if (!marked[w]) {
    				color[w] = !color[v];
    				dfs(G, w);
    			} else if (color[w] == color[v])
    				isTwoColorable = false;
    	}
    
    	public boolean isBipartite() {
    		return isTwoColorable;
    	}
    }



    展开全文
  • DFS算法初步

    2021-05-05 23:24:39
    是在图论题目里面一个重要的算法。 从我这个菜鸟的理解来讲,这个算法可以解决的问题是属于小数据且拥有树状分支的题目,字母D和‘深度’,在我看来可以理解为与题目所给出的根节点到叶子结点所经过的结点的数量,其...

    算法DFS(深度优先搜索)入门

    作为一个刚刚接触算法竞赛的大一新生,首次发博客的我在此希望能在csdn里面来记录我自己的成长。
    DFS:全称是Depth First Search
    是在图论题目里面一个重要的算法。
    从我这个菜鸟的理解来讲,这个算法可以解决的问题是属于小数据且拥有树状分支的题目,字母D和‘深度’,在我看来可以理解为与题目所给出的根节点到叶子结点所经过的结点的数量,其名为深度优先搜索,可以理解为将深度作为参考点将所有数据遍历的过程。
    DFS算法的基本思想是利用函数的递归将题目所给出的条件树中的结点进行访问和判断操作,假设给出一个深度已知或者已知最大深度判断条件的树,从根结点出发,遇到岔路口时选择随机一条道路,依次经过各个结点,到达最大深度或者满足最大深度时返回上一结点,再从上一节点未经过的道路出发,达到深度最大处,依此类推,直到所有结点(包含叶子结点)均遍历。
    例如
    在这里插入图片描述
    此树的遍历条件可以为A B D I K I D B E J E B F A C G L G M O G C H N P(此排序为先序遍历)
    需要有一个或者多个数作为深度依据来对是否继续进行递归操作进行判断,例如例题一中的
    dep
    变量,在dep达到最大值m时停止递归。

    我在此用两个简单的例题来作为解释;
    1.(第一题取自acwing的01背包问题 注:本题数据庞大时应该使用动态规划的算法来解决

    题目给出一个最大容量和若干的物品的价值和大小问能够装入背包的最大的价值为多少

    #include<bits/stdc++.h>//万能头文件,打竞赛的同学可以记下来
    using namespace std;
    const int N=1005;
    int maxV,m,va[N],V[N],maxva=0;/*maxV为背包容量,m为所给的物品数量,maxva为能够容纳的最大价值,va和V数组作为物品价值和物品的大小*/
    int main(){//这里我将主函数写在前面方便理解
    	void DFS(int dep,int sumV,int sumva);
    	scanf("%d%d",&m,&maxV);
    	for(int i=0;i<m;i++)
    	scanf("%d%d",&V[i],&va[i]);
    	DFS(0,0,0);
    	printf("%d",maxva);
    	return 0;
    }
    void DFS(int dep,int sumV,int sumva){//dep作为深度,sumV和sumva作为容量和价值的总和
    	if(dep==m||sumV>maxV)return;//当深度为最大或者物品的总体积大于背包容积时,深度最大时即为所有深度所在的物品均已被选择或者排除完毕,返回,不再进行递归
    	if(sumva>maxva)maxva=sumva;
    	DFS(dep+1,sumV+V[dep],sumva+va[dep]);//选择该深度下的物品加入背包
    	DFS(dep+1,sumV,sumva);//不选择该深度下的物品加入背包
    }
    

    输入输出
    在这里插入图片描述

    理解以上算法的关键是理解递归的作用是是否将该深度的物品加入至背包中。

    2.

    题目给出矩阵让我们求出其上下左右和其本身都为一的个数,如果一在边缘,则只需考虑有数字的邻接部分。

    #include<bits/stdc++.h>
    using namespace std;
    const int N=1005;
    int mi[N][N],pan[N][N],col,row;//建立mi数组来存储矩阵块,建立pan数组来判断是否被遍历过,col和row分别来存储行和列
    int bex[4]={0,0,-1,1},bey[4]={1,-1,0,0},m=0;//建立bex和bey函数可以在遍历上下左右的数时写的更加简便
    
    int main(void){//这里我将主函数放在前面方便理解 
    	void DFS(int x,int y); 
    	scanf("%d%d",&col,&row);
    	for(int i=0;i<col;i++)
    	for(int j=0;j<row;j++)
    	scanf("%d",&mi[i][j]);
    	memset(pan,0,sizeof(pan));//pan数组中所有的值全部置为0 
    	DFS(0,0);//从(0,0)开始进行递归 
    	printf("%d",m);
    }
    
    void DFS(int x,int y){//将x和y作为深度依据来判断是否该返回 
    	if(x>=col||y>=row||pan[x][y]!=0)return;//当x或者y深度达到时或者该坐标点已经判断过时开始返回 
    	pan[x][y]++;//将该坐标标记表示该坐标已被判断是否符合题目要求
    	m++;//m值加一,在接下来的循环中如果不满足题目的条件则复原m值
    	for(int i=0;i<4;i++){
    		if(x+bex[i]>=0&&x+bex[i]<col&&y+bey[i]>=0&&y+bey[i]<row)//判断其周边的四个点是否都是在图中 
    			if(mi[x+bex[i]][y+bey[i]]==0||mi[x][y]==0){//如果四个点有其中一个为零或者其中该点为0则复原m值 
    				m--;
    				break;
    			}
    		}
    	DFS(x+1,y);//以扩散方式遍历图中点 
    	DFS(x,y+1);
    	DFS(x+1,y+1);
    }
    

    输入输出:在这里插入图片描述
    本篇文章是在基于对算法笔记的学习以后所写,以上两题在算法笔记272页和277页均有详解,第二题例题在算法笔记上的答案为四,我们用最传统的手数可知答案为5.

    这是我这个菜鸟第一次写这种博客类文章,还有许多不完美之处多多包涵。

    展开全文
  • #include using namespace std; int s[1010][1010], vist[1010], n; void create(int m) {  int u, v;  while(m--)  {  cin>>u>>v;  s[u][v] = 1;  } } void DFS(int x) {

    数据结构实验之图论三:判断可达性

    Time Limit: 1000MS Memory Limit: 65536KB

    Problem Description

     在古老的魔兽传说中,有两个军团,一个叫天灾,一个叫近卫。在他们所在的地域,有n个隘口,编号为1..n,某些隘口之间是有通道连接的。其中近卫军团在1号隘口,天灾军团在n号隘口。某一天,天灾军团的领袖巫妖王决定派兵攻打近卫军团,天灾军团的部队如此庞大,甚至可以填江过河。但是巫妖王不想付出不必要的代价,他想知道在不修建任何通道的前提下,部队是否可以通过隘口及其相关通道到达近卫军团展开攻击。由于n的值比较大(n<=1000),于是巫妖王找到了擅长编程的你 =_=,请你帮他解决这个问题,否则就把你吃掉变成他的魔法。为了拯救自己,赶紧想办法吧。

     

    Input

     输入包含多组,每组格式如下。

    第一行包含两个整数n,m(分别代表n个隘口,这些隘口之间有m个通道)。

    下面m行每行包含两个整数a,b;表示从a出发有一条通道到达b隘口(注意:通道是单向的)。

    Output

     如果天灾军团可以不修建任何通道就到达1号隘口,那么输出YES,否则输出NO。

     

    Example Input

    2 1
    1 2
    2 1
    2 1

    Example Output

    NO
    YES
    

    Hint


    #include<bits/stdc++.h>

    using namespace std;
    int s[1010][1010], vist[1010], n;
    void create(int m)
    {
        int u, v;
        while(m--)
        {
            cin>>u>>v;
            s[u][v] = 1;
        }
    }
    void DFS(int x)
    {
        int i;
        vist[x] = 1;
        for(i = 0; i < n; i++)
        {
            if(vist[i]==0&&s[x][i]==1)
            {
                s[x][i] = 0;
                DFS(i);
            }
        }
    }
    int main()
    {
        int m;
        while(cin>>n>>m)
        {
            memset(s,0,sizeof(s));
            memset(vist,0,sizeof(vist));
            create(m);
            DFS(n);
            if(vist[1]==1)
                cout<<"YES"<<endl;
            else
                cout<<"NO"<<endl;
        }
        return 0;
    }
    展开全文
  • DFS算法

    2014-08-27 15:57:47
    最近看了一些图论的基本知识,

    最近看了一些图论的基本知识。先说一下图的邻接表表示方法:

    //有向图邻接表
    //邻接表存储图的思想很简单,首先构造一个包含 节点编号、出边list、入边list  的结构体的数组
    //出入边list是用来存储节点的出入情况
    //下面是我用c++写的例子
    #include<iostream>
    #include<vector>
    #include<list>
    using namespace std;
    
    struct Data{
    	int id;//点的编号
    	int weight;//权值
    };
    struct NodeList{
    	int id;//编号
    	list<Data> outList;//出边表
    	list<Data> inList;//入边表
    	NodeList(int i):id(i) {}
    };
    struct Edge{
    	int id1;
    	int id2;
    	int weight;
    };
    void NodeInit(int n, vector<NodeList>& vNode){
    	for (int i = 0; i < n; ++i)
    		vNode.push_back(NodeList(i));
    }
    void EdgeInit(const vector<Edge> &vedge, vector<NodeList>& vNode){
    	for (vector<Edge>::const_iterator i =vedge.begin(); i != vedge.end(); ++i){
    		vNode[i->id1-1].outList.push_back({ i->id2-1, i->weight });
    		vNode[i->id2-1].inList.push_back({ i->id1-1, i->weight });
    	}
    }
    int main(){
    	vector<NodeList> vNode;
    	vector<Edge> vedge{ { 1, 2, 1 }, { 2, 3, 1 }, { 2, 5, 1 }, { 2, 6, 1 },
    	{ 3, 5, 1 }, { 4, 3, 1 }, { 5, 2, 1 }, { 5, 4, 1 }, { 6, 7, 1 } };
    	NodeInit(7, vNode);
    	EdgeInit(vedge, vNode);
    	//分别输出每个定点的出度和入度
    	for (int i = 0; i < 7; ++i){
    		cout << vNode[i].outList.size() << ' ' ;
    	}
    	cout << endl;
    	for (int i = 0; i < 7; ++i){
    		cout << vNode[i].inList.size() << ' ';
    	}
    	return 0;
    }

    DFS深度优先搜索算法,自己写的例子

    //DFS深度优先搜索算法
    #include<iostream>
    #include<list>
    #include<vector>
    #include<algorithm>
    using namespace std;
    struct Data{
    	int id;//点的编号
    	int weight;//权值
    	bool operator <(const Data& data) const{
    		return id < data.id;
    	}
    };
    struct NodeList{
    	int id;//编号
    	list<Data> degree;//边链表
    	NodeList(int i):id(i) {}
    	
    };
    struct Edge{
    	int id1;
    	int id2;
    	int weight;
    };
    void NodeInit(int n, vector<NodeList>& vNode){
    	for (int i = 0; i < n; ++i)
    		vNode.push_back(NodeList(i));
    }
    void EdgeInit(const vector<Edge> &vedge, vector<NodeList>& vNode){
    	for (vector<Edge>::const_iterator i =vedge.begin(); i != vedge.end(); ++i){
    		Data data1 = { i->id2 - 1, i->weight };
    		Data data2 = { i->id1 - 1, i->weight };
    		vNode[i->id1 - 1].degree.push_back(data1);
    		vNode[i->id2 - 1].degree.push_back(data2);
    	}
    }
    void dfs(const vector<NodeList> vNode, int id,char*flag){
    	flag[id] = 1;
    	cout << id + 1 << endl;
    	for (list<Data>::const_iterator i = vNode[id].degree.begin(); i != vNode[id].degree.end(); ++i){
    		if (!flag[i->id]){
    			dfs(vNode, i->id, flag);
    		}
    		
    	}
    
    }
    int main(){
    	//邻接表 表示图
    	vector<Edge> vedge{ { 1, 2 }, { 1, 7 }, { 1, 5 }, { 2, 3 }, { 3, 4 }, {2,5}
    	, { 6, 5 }, { 6, 7 }, { 6, 8 }, { 8, 9 } };
    	vector<NodeList> vNode;
    	NodeInit(9, vNode);
    	EdgeInit(vedge, vNode);
    	for (int i = 0; i < 9; ++i)
    		vNode[i].degree.sort();
    	//从节点1开始DFS
    	char flag[9] = { 0 };//访问标志
    	dfs(vNode, 0, flag);
    
    	return 0;
    }

    DFS深度优先算法,解决实际问题——小狗逃离问题

    //小狗逃离问题
    //输入文件包括多个测试数据,每个测试数据的第一行为3个整数:N M T(1<N,M<7,0<T<50),分别代表
    //迷宫的长和宽,以及迷宫的门会在第T秒时刻开启。
    //接下来的N行信息给出了迷宫的格局,每行有M个字符
    //X:墙壁  S:小狗位置 D:出口 .:空的方格
    //输入以三个0结束
    
    #include<iostream>
    using namespace std;
    
    unsigned char start = 0, des = 0;//起始位置,前4位后4位分别表示 横纵坐标
    unsigned char edge = 0;//边界
    int N, M, T;
    char **map;
    bool if_yes;
    int mov[4][2] = { { -1, 0 }, { 1, 0 }, { 0, -1 }, { 0, 1 } };
    void dfs(unsigned char loc ,int step){//loc:当前位置,step:已用步数,deadline:需要的步数
    	if (loc == des){
    		cout << "YES" << endl;
    		if_yes = true;
    		return ;
    	}
    	for (int i = 0; i < 4; ++i){
    		unsigned char newloc = 0;
    		newloc |= ((loc >> 4) + mov[i][0]) << 4;
    		newloc |= ((loc & 0x0f) + mov[i][1]) & 0x0f;
    		if ((newloc >> 4) < (edge >> 4) && (newloc & 0x0f) < (edge & 0x0f)
    			&& map[newloc >> 4][newloc & 0x0f] != 'x'
    			&&step < T){
    			map[loc >> 4][loc & 0x0f] = 'x';
    			dfs(newloc, step + 1);
    			if (if_yes)
    				return;
    			map[loc >> 4][loc & 0x0f] = '.';
    		}
    	}
    }
    
    int main(){
    	FILE* pf = NULL;
    	freopen_s(&pf,"c:\\acm_input.txt", "r", stdin);
    
    	while (cin >> N >> M >> T){
    		if_yes = false;
    		int count = 0;//记录空方格数
    		if (N == 0)
    			break;
    		map = new char*[N];//N行M列的矩阵
    		for (int i = 0; i < N; ++i)
    			map[i] = new char[M];
    		for (int i = 0; i < N; ++i){//读入数据
    			for (int j = 0; j < M; ++j){
    				cin >> map[i][j];
    				if (map[i][j] == 's'){//记录起始位置
    					start = 0;//这里忘记清零,好不容易才发现 蛋疼
    					start |= (i << 4);
    					start |= j;
    				}
    				if (map[i][j] == 'd'){
    					des = 0;
    					des |= (i << 4);
    					des |= j;
    				}
    				if (map[i][j] == '.')
    					++count;
    			}
    		}
    		if (count < T - 1){
    			cout << "NO" << endl;
    			continue;
    		}
    		edge = 0;
    		edge |= (N << 4);
    		edge |= M;
    		dfs(start, 0);
    		if (!if_yes)
    			cout << "NO" << endl;
    		for (int i = 0; i < N; ++i)
    			delete[] map[i];
    	}
    	return 0;
    }

    上面代码是装文艺用的,下面是普通代码:

    #include<iostream>
    #include<cmath>
    using namespace std;
    
    
    int sx, sy, dx, dy;
    int N, M, T;
    char **map;
    bool if_yes;
    int mov[4][2] = { { -1, 0 }, { 1, 0 }, { 0, -1 }, { 0, 1 } };
    void dfs(int x,int y,int step){
    	if (x == dx&&y==dy&&step==T){
    		cout << "YES" << endl;
    		if_yes = true;
    		return;
    	}
    	int dis = abs(x - dx) + abs(y - dy);//距离最短步数
    	int left_step = T - step;//剩余要走的步数
    	if (dis > left_step || (left_step - dis) % 2 )
    		return;
    	for (int i = 0; i < 4; ++i){
    		if (x + mov[i][0] >= 0 && x + mov[i][0] < N
    			&&y + mov[i][1] >= 0 && y + mov[i][1] <M
    			&&map[x + mov[i][0]][y + mov[i][1]] != 'x'
    			&&step<T){
    			map[x][y] = 'x';
    			dfs(x + mov[i][0], y + mov[i][1], step + 1);
    			if (if_yes)
    				return;
    			map[x][y] = '.';
    		}
    	}
    }
    
    int main(){
    	FILE* pf = NULL;
    	freopen_s(&pf, "c:\\acm_input.txt", "r", stdin);
    
    	while (cin >> N >> M >> T){
    		if_yes = false;
    		if (N == 0)
    			break;
    		map = new char*[N];//N行M列的矩阵
    		int count = 0;
    		for (int i = 0; i < N; ++i)
    			map[i] = new char[M];
    		for (int i = 0; i < N; ++i){//读入数据
    			for (int j = 0; j < M; ++j){
    				cin >> map[i][j];
    				if (map[i][j] == 's'){//记录起始位置
    					sx = i;
    					sy = j;
    				}
    				if (map[i][j] == 'd'){
    					dx = i;
    					dy = j;
    				}
    				if (map[i][j] == '.')
    					++count;
    			}
    		}
    		if (count < T - 1){
    			cout << "NO" << endl;
    			continue;
    		}
    		dfs(sx,sy, 0);
    		if (!if_yes)
    			cout << "NO" << endl;
    		for (int i = 0; i < N; ++i)
    			delete[] map[i];
    	}
    	return 0;
    }
    


    油田问题和代码如下:

    题目描述:

    GeoSurvComp地质探测公司负责探测地下油田。每次GeoSurvComp公司都是在一块长方形的土地上来探测油田。在探测时,他们把这块土地用网格分成若干个小块,然后逐个分析每块土地,用探测设备探测地下是否有油田。土地底下有油田则成为pocket,如果两个pocket相邻,则认为是同一块油田,油田可能覆盖多个pocket。试计算长方形的土地上有多少个不同的油田。

    输入描述:

    输入文件中包含多个测试数据,每个测试数据描述了一个网格。每个网格数据的第1行为两个整数:m、n,分别表示网格的行和列;如果m=0,则表示输入结束,否则1<=m<=100,1<=n<=100。接下来有m行数据,每行数据有n个字符(不包括行结束符)。每个字符代表一个小方块,如果为“*”,则代表没有石油,如果为“@”,则代表有石油,是一个pocket。

    输出描述:

    对输入文件中的每个网格,输出网格中不同的油田数目。如果两块不同的pocket在水平、垂直或者对角线方向上相邻,则被认为属于同一块油田。每块油田所包含的pocket数目不会超过100。

    样例输入:

    5 5

    ****@

    *@@*@

    *@**@

    @@@*@

    @@**@

    样例输出:

    2

    #include<iostream>
    using namespace std;
    int mv[8][2] = { { -1, 0 }, { 1, 0 }, { 0, -1 }, { 0, 1 }, 
    { 1, 1 }, { 1, -1 }, { -1, 1 }, { -1, -1 } };
    int m, n;
    char** map;
    void dfs(int x, int y){
    	map[x][y] = '*';
    	for (int i = 0; i < 8; ++i){
    		if ((x + mv[i][0]) >= 0 && (x + mv[i][0] < m)
    			&& (y + mv[i][1] >= 0) && (y + mv[i][1] < n)
    			&& map[x + mv[i][0]][y + mv[i][1]] == '@'){
    			dfs(x + mv[i][0], y + mv[i][1]);
    		}
    	}
    	return;
    }
    int main(){
    	FILE* pf = NULL;
    	freopen_s(&pf, "c:\\acm_input.txt", "r", stdin);
    
    	while (cin >> m >> n){
    		if (m == 0)
    			return 0;
    		map = new char*[m];
    		int count = 0;
    		for (int i = 0; i < m; ++i){
    			map[i] = new char[n];
    			for (int j = 0; j < n; ++j)
    				cin >> map[i][j];
    		}
    		for (int i = 0; i < m; ++i){
    			for (int j = 0; j < n; ++j){
    				if (map[i][j] == '@'){
    					dfs(i, j);
    					++count;
    				}
    			}
    		}
    		cout << count << endl;
    	}
    	return 0;
    }



    展开全文
  • 图论算法DFS与BFS

    2017-08-26 23:01:00
    DFS算法图论部分中最基本的算法之一。对于算法入门者而言,这是一个必须掌握的基本算法。它的算法思想可以运用在很多地方,利用它可以解决很多实际问题,但是深入掌握其原理是我们灵活运用它的关键所在。 ...
  • 深度优先遍历(Depth First Search, 简称 DFS) 与广度优先遍历(Breath First Search)是图论中两种非常重要的算法,生产上广泛用于拓扑排序,寻路(走迷宫),搜索引擎,爬虫等,也频繁出现在 leetcode,高频面试...
  • DFS深度优先遍历算法,VS2010环境,可运行,数据是自己随便编的
  • 不仅如此,dfs,bfs不仅仅能够解决图论的问题,在其他问题的搜索上也是最基础(但是策略不同)的两种经典算法。 并且五大经典算法的回溯算法其实也是dfs的一种。dfs,bfs基础能够解决搜索类问题的大部分情况,只不过...
  • Kruskal算法 对边排序,选出n-1条路径最短的边。即得到一个最小生成树。 在选边过程中,需要判断,两点是否已经连通。可以使用dfs或bfs但是效率很低,这里使用并查集来判断图中的两点是否已经连通.。 import java....
  • 图论算法基础-BFS与DFS

    2017-08-16 11:02:38
    注意,这两种算法图论的基础,很多后续算法都是建立与两者之上,话不多说,让我们进入正题。宽度优先搜索思想:假设某个点为图的根节点,把图想象成一颗倒过来的树,每层每层的向下进行搜索,直到遇见正确的结果,...
  • 目录1介绍2 图的基本概念2.1 定义性质2.2 分类3 图的存储方式3.1 链接矩阵3.2 链接表4 图的遍历4.1 dfs4.2 bfs5 dijkstra算法6 动态规划hp7 简单封装一个图类 1介绍 2 图的基本概念 2.1 定义性质 2.2 分类 3 图的...
  • 图论中, 图的直径是指任意两个顶点间距离的最大值. (距离是两个点之间的所有路的长度的最小值) 从v1开始进行bfs遍历,找到距离最大的点,即为直径的一个端点v2; 将所有点距离 v1 的长度进行数组存储,将所有点距离 ...
  • 算法模板 图论

    2021-06-10 01:01:05
    算法模板 图论有向图的强连通分量(Kosaraju) 有向图的强连通分量(Kosaraju) 测试:hdu 1269 const int N = 1e5 + 10; struct Edge{ int to, next; }e1[N], e2[N]; int head1[N], tot1, head2[N], tot2; bool ...
  • 题目:排列数字 给定一个整数 n,将数字 1∼n 排...如果纯粹用暴力去做,那么并不是题目想让我们的做法,这里题目想让我们用DFS深度优先搜索算法去做。 我们开始寻找第一个数,如例子来说,我们第一次可以选择1,2,3,
  • 算法基础课—搜索与图论(一)DFS、BFS、树、图的存储方式及搜索深度优先搜索 DFS核心——回溯和剪枝回溯剪枝算法思想整体结构算法模板——来自于排列数的题目排列数字题目算法思想代码n皇后问题题目方法一代码方法...
  • 基本图算法(图的表示/广度优先搜索/深度优先搜索/拓扑排序/强连通分量)
  • 图论》——深度优先搜索算法(DFS)

    千次阅读 2015-07-31 09:55:35
    十大算法之广度优先遍历: 深度优先搜索遍历类似于树的先序遍历。假定给定图G的初态是所有顶点均未被访问过,在G中任选一个顶点i作为遍历的初始点,则深度优先搜索递归调用包含以下操作: (1)访问搜索到的未被...
  • 图论算法——dfs求有向图和无向图两点间所有路径

    千次阅读 多人点赞 2019-06-12 09:28:24
    DFS大法好! DFS作为搜索算法,最常...我在这里就介绍一下dfs求两点的的所有路径,这个算法最开始在数据结构大作业里面用到了,当时费了一番劲写出来后,就想oj题里面这么变态的算法肯定不会出,后来还真的见过了。。。
  • DFS在搜索算法中,常常利用函数递归实现暴力枚举,而DFS图论中,则是对图的每个结点的遍历。 DFS最显著的特征在于其 递归调用自身 ,在遍历图时,对其访问的点打上访问标记,在遍历时跳过标记过的点,以确保每个点...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 745
精华内容 298
关键字:

dfs算法图论