Spicy Restaurant(多元BFS)4星
题意:
给你一个 n n n个点 m m m条边的无向图,每个点有一个权值 w w w, q q q次询问问从点 a a a出发走到权值小于等于 b b b的点的最小距离,不能满足输出-1
1 ≤ n , m ≤ 1 0 5 1\leq n,m\leq 10^5 1≤n,m≤105
1 ≤ w i , b i ≤ 100 1\leq w_i,b_i\leq 100 1≤wi,bi≤100
1 ≤ a i ≤ n 1\leq a_i\leq n 1≤ai≤n
题解:
因为权值的范围比较小,所以我们可以按照权值跑BFS记录每种情况每个点到权值 w w w的最小距离
注意题目要求小于等于,所以最后还需要更新一下最小值
#include<bits/stdc++.h>
#define endl '\n'
#define x first
#define y second
using namespace std;
typedef long long ll;
typedef pair<int,int>PII;
const int N=1e5+10,M=2*N;
int h[N],e[M],ne[M],idx;
int g[N],dist[110][N];
int q[N];
int n,m,k;
void add(int a,int b){
e[idx]=b,ne[idx]=h[a],h[a]=idx++;
}
void bfs(int u){
for(int i=1;i<=n;i++) dist[u][i]=-1;
int hh=0,tt=-1;
for(int i=1;i<=n;i++){
if(g[i]==u){
dist[u][i]=0;
q[++tt]=i;
}
}
while(hh<=tt){
int t=q[hh++];
for(int i=h[t];~i;i=ne[i]){
int j=e[i];
if(dist[u][j]!=-1) continue;
dist[u][j]=dist[u][t]+1;
q[++tt]=j;
}
}
}
int main(){
ios::sync_with_stdio(false);
cin.tie(0);cout.tie(0);
cin>>n>>m>>k;
memset(h,-1,sizeof h);
for(int i=1;i<=n;i++) cin>>g[i];
while(m--){
int a,b; cin>>a>>b;
add(a,b),add(b,a);
}
for(int i=1;i<=100;i++) bfs(i);
for(int i=1;i<=n;i++){
for(int j=2;j<=100;j++){
if(dist[j][i]==-1) dist[j][i]=dist[j-1][i];
else if(dist[j-1][i]!=-1) dist[j][i]=min(dist[j][i],dist[j-1][i]);
}
}
while(k--){
int a,b; cin>>a>>b;
cout<<dist[b][a]<<endl;
}
return 0;
}
Don’t Really Like How The Story Ends(贪心+dfs)4星
题意:
已知一个 n n n个点 m m m条边的无向图,问最少加多少条边才能使从1出发dfs得到1~n的一个序列
题解:
设当前点为 x x x,且 x x x的上一个点为 y y y
- 当x直接与 x + 1 x+1 x+1相连时,可以直接走到 x + 1 x+1 x+1
- 若
x
x
x不与
x
+
1
x+1
x+1直接相连
- 当 x x x不与大于 x + 1 x+1 x+1的点相连时,倘若 y y y与 x + 1 x+1 x+1相连则不需要加边,若 y y y也不与 x + 1 x+1 x+1相连则在 y y y加边也不会使当前答案更差,所以我们可以选择回溯到结点 y y y进行判断
- 当 x x x与大于 x + 1 x+1 x+1的点 t t t相连时,必须加一条边
- 上述情况可能有 t > > x + 1 t>>x+1 t>>x+1,需要多次重复加边知道 n o w = t now=t now=t
#include<bits/stdc++.h>
#define endl '\n'
#define x first
#define y second
using namespace std;
typedef long long ll;
typedef pair<ll,ll>PII;
const int N=1e5+10;
int n,m,ans,now;
vector<int>ve[N];
void dfs(int u){
if(u>n) return ;
for(auto p:ve[u]){
if(p<now) continue;
while(p>=now){//上述情况可能有$t>>x+1$,需要多次重复加边知道now=t
if(p==now) now++,dfs(now-1);
else now++,ans++,dfs(now-1);
}
}
}
void solve(){
cin>>n>>m;
ans=0,now=2;//直接从2开始判断
for(int i=1;i<=n;i++) ve[i].clear();
while(m--){
int a,b; cin>>a>>b;
if(a>b) swap(a,b);
ve[a].push_back(b);
}
ve[1].push_back(n+1);//加一条到n+1的边作为边界
for(int i=1;i<=n;i++) sort(ve[i].begin(),ve[i].end());
dfs(1);
cout<<ans<<endl;
}
int main(){
ios::sync_with_stdio(false);
cin.tie(0);cout.tie(0);
int T=1;
cin>>T;
while(T--){
solve();
}
return 0;
}