struct Edge{
int d;//边的终点
int l;//边的权值
};
vector<vector<Edge>> G(MAXV);
深度优先遍历图上的所有结点
const int MAXV = 1010;
int visited[MAXV] = { 0 }; //将所有的点都标记为新点
void DFS(v)
{
if (visited[v])
{
...
return;
}
...
visited[v] = 1;
对和v相邻的每个结点u
{
DFS(u);
}
}
int main()
{
int n; //n为图中顶点的个数
for(int i = 1;i<=n;i++)
{
if(!visited[v]) //如果结点v未被访问,则结点v所在的连通分量都未被访问
DFS(v); //深搜之后,结点v所在的连通分量中的结点都被遍历一遍
}
}
#include
#include
#include
using namespace std;
const int MAXV = 1000;
struct Edge {
int d;
};
vector<vector<Edge>> G(MAXV);
int visited[MAXV] = { 0 };
int maxNum = 0; //所有连通分量中结点个数的最大值
int num = 0; //当前搜索中结点的个数
void dfs(int v)
{
if (visited[v])
{
return;
}
visited[v] = 1;
num++;
for (int i = 0; i < G[v].size(); i++)
{
dfs(G[v][i].d);
}
}
int main()
{
int m;
while (scanf("%d", &m) != EOF)
{
maxNum = 0;
for (int i = 1; i <= MAXV; i++)
G[i].clear();
memset(visited, 0, sizeof(visited));
for (int i = 1; i <= m; i++)
{
int s, d;
Edge r;
cin >> s >> d;
r.d = d;
G[s].push_back(r);
r.d = s;
G[d].push_back(r);
}
for (int i = 1; i <= MAXV; i++)
{
if (!visited[i])
{
num = 0;
dfs(i);
maxNum = max(maxNum, num);
}
}
cout << maxNum << endl;
}
system("pause");
return 0;
}
思路:简单的dfs应用,每次深搜都会遍历一个连通分量
求解图中的连通分量的个数和所有连通分量中结点个数的最大值
连通分量的个数:RoomNum
所有连通分量中结点个数的最大值:maxRoomArea
//POJ 2815 城堡问题
#include
#include
using namespace std;
const int MAXV = 60;
int G[MAXV][MAXV];
int maxRoomArea = 0;
int RoomArea = 0; //当前的房间的面积
int RoomNum = 0; //房间的数量
int visited[MAXV][MAXV];
void DFS(int i, int j)
{
if (visited[i][j])
return;
RoomArea++;
visited[i][j] = 1;
if ((G[i][j] & 1) == 0)
DFS(i, j - 1);
if ((G[i][j] & 2) == 0)
DFS(i-1, j );
if ((G[i][j] & 4) == 0)
DFS(i, j + 1);
if ((G[i][j] & 8) == 0)
DFS(i+1, j);
}
int main()
{
int n, m;//n为行数,m为列数
scanf("%d", &n);
scanf("%d", &m);
for (int i = 1; i <= n; i++)
{
for (int j = 1; j <= m; j++)
{
cin >> G[i][j];
visited[i][j] = 0;
}
}
for (int i = 1; i <= n; i++)
{
for (int j = 1; j <= m; j++)
{
if (!visited[i][j])
{
RoomNum++;RoomArea = 0;
DFS(i, j);
maxRoomArea = max(maxRoomArea, RoomArea);
}
}
}
cout << RoomNum << endl;
cout << maxRoomArea << endl;
return 0;
}
图为连通的,一般只有一个连通分量
模板一 先dfs,然后再访问结点v
const int MAXV = 1010;
int visited[MAXV] = { 0 }; //将所有的点都标记为新点
int N; //N为终点
void DFS(v)
{
if (v == N)
{
...
return;
}
visited[v] = 1;
对和v相邻的每个结点u
{
if(!visited[u])
{
DFS(u);
}
}
visited[v] = 0; //有的题需要将原来的状态还原,再进行下一次的循环
}
int main()
{
int n; //n为图中顶点的个数
DFS(1); //深搜之后,结点v所在的连通分量中的结点都被遍历一遍
}
模板二 先访问结点v,然后再dfs
const int MAXV = 1010;
int visited[MAXV] = { 0 }; //将所有的点都标记为新点
int N; //N为终点
void DFS(v)
{
if (v == N)
{
...
return;
}
对和v相邻的每个结点u
{
if(!visited[u])
{
visited[u] = 1;
DFS(u);
visited[u] = 0; //有的题需要将原来的状态还原,再进行下一次的循环
}
}
}
int main()
{
int n; //n为图中顶点的个数
visited[1] = 1;
DFS(1); //深搜之后,结点v所在的连通分量中的结点都被遍历一遍
}
思路:按照行号进行深搜
初始状态:第0行
目标状态:第n行
//N皇后
#include
#include
using namespace std;
const int MAXN = 100; //最多的行数
int n;
int pos[MAXN]; //pos[i]:第i行皇后所放的列数
int total; //放置的方案数
int visited[3][MAXN]; //visited[0]:保存列的信息;visited[1]:保存主对角线的信息;visited[0]:保存辅对角线的信息
void dfs(int row)
{
//按照行号来深搜,row为当前搜索的行数
if (row == n)
{
total++;
for (int i = 0; i < n; i++)
{
for (int j = 0; j < n; j++)
{
if (j == pos[i]) cout << "*"<<" ";
else cout << "o" << " ";
}
cout << endl;
}
cout << endl;
return;
}
for (int i = 0; i < n; i++)
{
if (!visited[0][i] && !visited[1][row - i + n] && !visited[2][row + i])
{
pos[row] = i;
visited[0][i] = 1;
visited[1][row - i + n] = 1;
visited[2][row + i] = 1;
dfs(row + 1);
visited[0][i] = 0;
visited[1][row - i + n] = 0;
visited[2][row + i] = 0;
}
}
}
int main()
{
total = 0;
scanf("%d", &n);
memset(visited, 0, sizeof(visited));
dfs(0);
cout << total << endl;
system("pause");
return 0;
}
dfs+剪枝 模板题
思路:使用可行性剪枝和最优性剪枝来减少dfs的时间复杂度
剪枝:当前搜索的状态不合法时,就跳到当前的搜索(使用 continue )
可行性剪枝:当到达结点a时,花费已经超过给定的K时,则剪枝
最优性剪枝:
#include
#include
#include
using namespace std;
struct Edge {
int d, l, c; //边的终点、边的长度、边的花费
};
const int INF = 0x3f3f3f3f;
vector<vector<Edge>> G(110);
int minLen = INF; //最短路径长度
int totalLen; //当前搜索路径的长度
int totalCost; //当前搜索路径的花费
int visited[110] = { 0 };
int K, N, R;
int mid[110][10010]; //mid[i][j]表示到达结点i,且花费为j元时的最短路径长度
void dfs(int v)
{
if (v == N)
{
minLen = min(minLen, totalLen);
return;
}
for (int i = 0; i < G[v].size(); i++)
{
Edge r = G[v][i];
//可行性剪枝
if (totalCost + r.c > K)
continue;
//最优性剪枝
if (totalLen + r.l >= minLen)
continue;
if (totalLen + r.l >= mid[r.d][totalCost + r.c])
continue;
visited[r.d] = 1;
totalLen += r.l;
totalCost += r.c;
mid[r.d][totalCost] = totalLen;
dfs(r.d);
//当去搜索下一个结点时,该结点可能通过r.d,故将r.d还原
visited[r.d] = 0;
totalLen -= r.l;
totalCost -= r.c;
}
}
int main()
{
Edge r; int s;
cin >> K >> N >> R;
for (int i = 0; i < R; i++)
{
cin >> s >> r.d >> r.l >> r.c;
G[s].push_back(r);
}
fill(mid[0], mid[0] + 110 * 10010, INF);
totalLen = 0;
totalCost = 0;
visited[1] = 1;
dfs(1);
if (minLen < INF)
{
cout << minLen << endl;
}
else
{
cout << "-1" << endl;
}
return 0;
}
#include
#include
#include
#include
using namespace std;
const int INF = 0x3f3f3f3f;
int G[7][7];
int vis[7][7];
int len; //当前搜索路径的长度
int minLen; //最短路径的长度
struct Node {
int x, y;
Node(int a, int b)
{
x = a;
y = b;
}
};
vector<Node> path;
vector<Node> minPath;
void dfs(int i, int j)
{
if (i == 5 && j == 5)
{
len++;
path.push_back(Node(i, j));
if (len < minLen)
{
minLen = len;
minPath.assign(path.begin(), path.end());
}
return ;
}
vis[i][j] = 1;
len++;
path.push_back(Node(i, j));
if (!vis[i][j - 1] && G[i][j - 1] != 1)
{
dfs(i, j - 1);
}
if (!vis[i][j + 1] && G[i][j + 1] != 1)
{
dfs(i, j + 1);
}
if (!vis[i-1][j] && G[i-1][j] != 1)
{
dfs(i-1, j );
}
if (!vis[i+1][j] && G[i+1][j] != 1)
{
dfs(i+1, j);
}
vis[i][j] = 0;
len--;
path.pop_back();
}
int main()
{
len = 0;
minLen = INF;
fill(G[0], G[0] + 7 * 7, 1);
memset(vis, 0, sizeof(vis));
for (int i = 1; i <= 5; i++)
{
for (int j = 1; j <= 5; j++)
{
cin >> G[i][j];
}
}
dfs(1, 1);
for (int i = 0; i < minPath.size(); i++)
{
cout << "(" << minPath[i].x - 1 << ", " << minPath[i].y - 1 << ")" << endl;
}
system("pause");
return 0;
}