最近看了一些图论的基本知识。先说一下图的邻接表表示方法:
//有向图邻接表
//邻接表存储图的思想很简单,首先构造一个包含 节点编号、出边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;
}