L. Spicy Restaurant
题意:
n个火锅店,辣度分别是w[i],有q个人,每个人能忍受的最大辣度是g,有m条边 连接火锅店。求每个人能够去的火锅店最短距离。
思路:
由于w<=100,则所以直接枚举一个权值k k,把所有w[i] = k的点作为源点做一次多源bfs 那么可以预处理dis[i][j]表示j点距离最近的辣味i多远
然后顺着更新一遍dis[i][j]=min(dis[i][j],dis[i-1][j]);
代码:
#include<bits/stdc++.h>
using namespace std;
#define N 200005
int n,m,q,inf,dis[105][N],w[N];
vector<int>ve[N];
void bfs(int c){
queue<int>q;
for (int i = 1; i <=n ; ++i) {
if(w[i]==c)q.push(i),dis[c][i]=0;
}
while (!q.empty()){
int u=q.front();
q.pop();
for (int i = 0; i < ve[u].size(); ++i) {
if(dis[c][ve[u][i]]!=inf)continue;
q.push(ve[u][i]);
dis[c][ve[u][i]]=dis[c][u]+1;
}
}
}
int main(){
memset(dis,0x3f,sizeof dis);
inf=dis[0][0];
cin>>n>>m>>q;
for (int i = 1; i <=n ; ++i) {
cin>>w[i];
}
for (int i = 0; i < m; ++i) {
int a,b;
cin>>a>>b;
ve[a].push_back(b),ve[b].push_back(a);
}
for (int i = 100; i >=1 ; --i)bfs(i);
for (int i = 1; i <=n ; ++i) {
for (int j = 1; j <=100 ; ++j) {
dis[j][i]=min(dis[j][i],dis[j-1][i]);
}
}
while (q--){
int a,b;
cin>>b>>a;
if(dis[a][b]==inf)
cout<<"-1"<<endl;
else
cout<<dis[a][b]<<endl;
}
}
2.E.
题意:
给一个n个节点的图,以及m条边,问需要加多少条边能dfs从1到n
思路:
- 题目中是按照dfs顺序给出编号,所以从1结点开始,第二个点必须是和2相连
- 1.如果结点1不和结点2相连,加边 ans++
- 2.如果相连遍历dfs(2),如果结点2和3相连dfs(3),依次类推
- 如果不和3相连并且不与其他任何结点相连,返回上一结点,因为在结点1加边结果不会比结2差
- 如果结点2和结点3以外的边相连接则需要加边ans++
代码:
#include<bits/stdc++.h>
using namespace std;
const int maxn = 1e5+100;
int t,n,m,u,v,ans,tot; //变量tot计算当前遍历到哪一个数
vector<int>edge[maxn];
void dfs(int u)
{
if(u == n+1) return;
for(auto x:edge[u])
{
if(x < tot) continue;
while( x >= tot )
{
if(x==tot) tot++, dfs(x);
else
{
tot++; ans++; dfs(tot-1);
}
}
}
}
int main()
{
scanf("%d",&t);
while(t--)
{
scanf("%d%d",&n,&m);
for(int i=1;i<=m;i++)
{
scanf("%d%d",&u,&v);
edge[u].push_back(v);
edge[v].push_back(u);
}
//题目中按照DFS顺序排列所以对邻接表中的元素排序
for(int i=1;i<=n;i++)
sort(edge[i].begin(), edge[i].end());
//保证1~n的点全部被遍历一遍
edge[1].push_back(n+1);
tot=2, ans=0;
dfs(1);
printf("%d\n",ans);
for(int i=1;i<=n;i++) edge[i].clear();
}
return 0;
}