2021ICPC 四川省赛(bfs+dp,dfs)
E. Don't Really Like How The Story Ends
题意
有一个图包含 \(n\) 个点,要求添加最少的边使得构成 \(1...n\) 的 \(dfs\) 序
数据范围
\(1<=n,m<=10^5\)
多组测试样例
输入
3
2 3
1 1
1 2
2 1
4 1
1 4
4 2
1 2
3 4
输出
0
2
1
分析
本着非必要的时候不添边的原则,只有当 \([1,i-1]\) 全部遍历完成时,且 \(i\) 节点没有一条合法的边时,才可以添加这条边;
如何判断一个节点存在合法边就是从当前叶子节点向上遍历,只要存在一个父节点联通 \(i\) 说明合法,如果到达 \(root=1\),还是没有便是不合法
$hint: $ 可能有很多节点都是游离的
代码
const int N = 1e5 + 5;
int n, m, k, _;
int a[N];
vector<int> g[N];
int ed, ans;
int vis[N];
void dfs(int u)
{
// vis[u] = 1;
for(int i = 0; i < g[u].size(); i ++){
int v = g[u][i];
if(v < ed) continue;
if(v == ed){
ed ++;
dfs(v);
}
else{
ans ++;
ed ++;
i --;
dfs(ed - 1);
}
}
while(ed <= n && u == 1){
ed ++;
ans ++;
dfs(ed - 1);
}
}
void clear()
{
for(int i = 1; i <= n; i ++) g[i].clear();
}
signed main()
{
// IOS;
rush(){
sdd(n, m);
rep(i, 1, m){
int x, y;
sdd(x, y);
if(x > y) swap(x, y);
if(x != y) g[x].pb(y);
}
for(int i = 1; i <= n; i ++){
sort(g[i].begin(), g[i].end());
g[i].erase(unique(g[i].begin(), g[i].end()), g[i].end());
}
ed = 2;
ans = 0;
dfs(1);
pd(ans);
clear();
}
// PAUSE;
return 0;
}
L. Spicy Restaurant
题意
有一个图包含 \(n\) 个点,每个节点都有一个辣度值,\(q\) 此询问,每次询问给出人的位置以及接受的最大辣度值,求最近的可以接受的辣度值离自己多远
数据范围
\(1<=n,m<=10^5\)
\(1<=q<=5*10^5\)
\(1<=a[i]<=100\)
输入
4 4 5
5 4 2 3
1 2
2 3
3 4
4 1
1 1
1 2
1 3
1 4
1 5
输出
-1
2
1
1
0
分析
设 \(dp[i][j]\) 当前 \(i\) 位置辣度值为 \(j\) 的最近距离
可以利用 \(bfs\) 求出来所有的值
题目建图不可以用 \(vector\),以下代码不可以保证通过
代码
const int N = 1e5 + 5;
int n, m, k, _;
int a[N];
int dp[N][100 + 5];
vector<int> g[N];
void bfs(int w)
{
queue<int> q;
for(int i = 1; i <= n; i ++){
if(a[i] == w){
q.push(i);
dp[i][w] = 0;
}
}
while(q.empty() == 0){
int u = q.front();
q.pop();
for(auto v : g[u]){
if(dp[v][w] != inf) continue;
dp[v][w] = min(dp[v][w], dp[u][w] + 1);
q.push(v);
}
}
}
signed main()
{
// IOS;
int q;
while(~ sddd(n, m, q)){
int maxx = 0;
rep(i, 1, n) sd(a[i]), maxx = max(maxx, a[i]);
rep(i, 0, n) rep(j, 0, maxx) dp[i][j] = inf;
int x, y;
rep(i, 1, m){
sdd(x, y);
g[x].pb(y);
g[y].pb(x);
}
for(int i = 1; i <= maxx; i ++){
bfs(i);
}
// rep(i, 1, n) rep(j, 1, 5) dbg(dp[i][j]);
for(int i = 1; i <= n; i ++){
for(int j = 1; j <= maxx; j ++){
dp[i][j] = min(dp[i][j], dp[i][j - 1]);
}
}
int pos, val;
while(q --> 0){
sdd(pos, val);
if(dp[pos][val] == inf) dp[pos][val] = -1;
pd(dp[pos][val]);
}
}
// PAUSE;
return 0;
}