2021四川省赛E
Don't Really Like How The Story Ends
题目大意
给图加边,使得一个可能的DFS序列刚好是从1到n
Time : 1000 ms
Memory: 262144 kB
解题思路及分析
第一次打正式比赛,场上E因为自己的nt行为T了好几发,这个是赛后补题
直接搜索,但是需要有一定条件
如果想要DFS序列刚好为从1到N,需要满足的条件:
- 如果与直接相连,则访问搜索
- 如果点存在没有访问的相邻节点且点不与点相连,此时必须将连接到上
- 如果点所有相邻节点都被访问了,可以与相连,也可以和从=>中路径上的任意一点相连,路径上的点都在递归栈里面,此时可以让点退栈,一直回到某个满足条件或的节点
- 如果第3点的点退栈一直到起点1号点都没有直接相连,说明存在不连通部分,此时必须加边,此时再去搜索不连通的部分,一直到全部搜索完
AC代码
#include <bits/stdc++.h>
typedef long long llong;
const int N = 1e5 + 5;
using namespace std;
vector<int> mp[N];
bool vis[N];
int cnt;
int n, m, nxt;
void dfs(int u) {
nxt++;
for (int i = 0; i < mp[u].size(); i++) {
int to = mp[u][i];
if (vis[to]) continue;
if (to == nxt) { // [1]
vis[nxt] = true;
dfs(nxt);
} else { // [2]
cnt++;
vis[nxt] = true;
dfs(nxt);
i--;
}
}
if (u == 1) { // [3] [4]
while (nxt <= n) {
vis[nxt] = true;
dfs(nxt);
cnt++;
}
}
}
int main() {
ios::sync_with_stdio(false);cin.tie(0);
int T; cin >> T;
while (T--) {
cin >> n >> m;
for (int i = 1; i <= n; i++) {
mp[i].clear();
vis[i] = false;
}
nxt = 1;
cnt = 0;
for (int i = 0; i < m; i++) {
int u, v;
cin >> u >> v;
if (u < v) mp[u].push_back(v);
if (u > v) mp[v].push_back(u); // 一个小优化,只由编号小的节点连接到编号大的节点
}
for (int i = 1; i <= n; i++) {
sort(mp[i].begin(), mp[i].end());
// 这里进行排序,就可以保证每次访问的节点都是最小的,方便判断刚刚解题思路中说的条件
// 不要用堆,亲测会T(场上nt的我)
}
vis[1] = true;
dfs(1);
cout << cnt << endl;
}
return 0;
}