グラフトラバーサルアプリケーション
稠密と図の隣接行列
図のスパース隣接テーブル。
問題:
ランダムに配向マップは、ポイントを削除すると、すべての我々はドットは、すべてが、その後、私たちは、この操作のランダムなポイントを削除する削除接続し、それぞれが一回行われ、元のマップk回に連続して行い、私たちは、元の外観を復元する計画を持っていると尋ねた:私たちは削除ポイントの後に見るたびに、接続性マップを高めるために、エッジの最小数を必要とします。
ソリューション:
原理:
私たちはそこにあるのn図の通信ブロック、B1、B2、B3 ... BNと仮定します 。(ブロック通信ポイント通信のコレクション)、我々は、少なくともN-1辺が通信ブロックを通信することができます。最後に大きな通信図を形成します。
実践:
マップは、削除ポイント、それぞれ再び深トラバーサルの観点、および、レコードアクセスは、このポイントが削除されている場合と仮定されている、またはポイントが訪問されている、と訪れていない場合、我々はこの点をスキップ我々はそれが通信ブロックであっても。
(内部ロジックは、次のとおりポイントこの時点トラバーサル深度がアクセスされていない前に、ポイントは、ブロックに記載されている必要があり、この時点で判定された場合には必ず、すべての点へのフルアクセスは、これに接続されますトラバーサルの深さは、通信ブロックで発見されていないため私たちもレコードを一定の深さトラバーサルので心配に我々は通信ブロックの他の点に注意してくださいアクセスされていない場合はありません、二次計算を同じトークンを防ぐために、もう一度、通信ブロックマークのすべてのポイントをその深さを横断しましたA)
#include <cstdio>
#include <cstring>
#include <vector>
using namespace std;
const int N = 1111;
/*
vector<int> G;变长一维数组
vector<int> G[n];二维数组,其中一个维度定长n,一个维度变长
*/
vector<int> G[N];
bool vis[N];
//深度遍历
int currentPoint;
void dfs(int v){
//v为顶点编号,有n个顶点,就有n种编号
//递归基为,判断该点是否访问过
if(v == currentPoint) return;//遇到被删点返回,因为点被删了与之相连的边也不存在了所以不需要访问它,回退到上一层。
//将该点标记为以访问
vis[v] = true;
//遍历从v点出发可以到达的顶点
for(int i = 0; i < G[v].size(); i++){
//若该点没有访问过,去访问
//G[v][i]访问的是v->i这条边的终点编号
if(vis[G[v][i]] == false){
dfs(G[v][i]);
}
}
}
int n, m, k;
int main(){
//输入n个顶点,m条边,k次查询、
//无向图边最多n(n-1)/2条
scanf("%d%d%d",&n, &m, &k);
for(int i = 0; i < m; i++){
int a, b;
scanf("%d%d", &a, &b);
//无向图为连接a-b的边
G[a].push_back(b);
G[b].push_back(a);
}
//对其k次删点,假装删,其实点还在表里,不过我们标记该点,不去访问它
for(int query = 0; query < k; query++){
scanf("%d", ¤tPoint);
//初始化,开辟vis内存位置,将数组vis的值初始化为flase
memset(vis, flase, sizeof(vis));
int block = 0;
for(int i = 1; i<= n; i++){
//核心判断,判断该点未被访问且不是被删点
if(i != currentPoint && vis[i] == false){
dfs(i);
block++;
}
}
printf("%d\n", block - 1);
}
return 0;
}