DFS算法

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

//有向图邻接表
//邻接表存储图的思想很简单,首先构造一个包含 节点编号、出边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;
}



评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值