Problem L. Spicy Restaurant
题意:
无向图的每个顶点有一个属性
w
i
w_i
wi,
Q
Q
Q 个询问,第
i
i
i 个询问给定顶
点
p
p
p 和阈值
a
a
a,问距离
p
p
p 最近的
w
i
≤
a
w_i \leq a
wi≤a 的
i
i
i 距离
p
p
p 有多远。
1
≤
w
i
≤
100
1 \leq w_i \leq 100
1≤wi≤100。
多源BFS
d
i
s
[
i
]
[
j
]
dis[i][j]
dis[i][j]表示从点
i
i
i到辣度为
j
j
j的最短火锅店距离
最后对于在
x
x
x点,能吃辣度为
k
k
k的人来说,答案是
d
i
s
[
x
]
[
j
]
(
j
≤
k
)
dis[x][j](j \leq k)
dis[x][j](j≤k)
关于输入输出的TLE
记得用
"
\
n
"
"\backslash n"
"\n",别用
e
n
d
l
endl
endl!!!不然会超时!!!
#include<bits/stdc++.h>
using namespace std;
#define endl "\n"
typedef long long ll;
const int N = 1e5 + 10;
int dis[N][110];
vector<int> v[N];
int m, n, q;
int w[N];
void bfs(int x)
{
queue<int> q;
for(int i = 1 ; i <= n ; i++)
if(w[i] == x)
q.push(i),dis[i][x] = 0;
while(q.size()){
auto t = q.front();q.pop();
for(auto u : v[t])
{
if(dis[u][x] != 0x3f3f3f3f) continue;
dis[u][x] = dis[t][x] + 1;
q.push(u);
}
}
}
int main()
{
ios::sync_with_stdio(false);
cin.tie(0),cout.tie(0);
memset(dis,0x3f,sizeof dis);
//scanf("%d%d%d",&n,&m,&q);
cin >> n >> m >> q;
for(int i = 1 ; i <= n ; i++) cin >> w[i];//scanf("%d",&w[i]);
for(int i = 0 ; i < m ; i++)
{
int a,b;
//scanf("%d%d",&a,&b);
cin >> a >> b;
v[a].push_back(b);
v[b].push_back(a);
}
for(int i = 1 ; i <= 100 ; i++) bfs(i);
for(int i = 1 ; i <= n ; i++)
for(int j = 2 ; j <= 100 ; j++)
dis[i][j] = min(dis[i][j],dis[i][j-1]);
while(q--)
{
int i,j;
//scanf("%d%d",&i,&j);
cin >> i >> j;
//printf("%d\n",((dis[i][j]==0x3f3f3f3f)?-1:dis[i][j]));
cout << ((dis[i][j]==0x3f3f3f3f)?-1:dis[i][j]) << endl;
}
}
E Don’t Really Like How The Story Ends
题意:
给出
n
n
n个点
m
m
m条边,问需要补充多少条边使得能够依次DFS遍历到顶点
1
−
n
1-n
1−n
思路:
- 如果 v v v与 v + 1 v + 1 v+1直接相连,则访问搜索 v + 1 v + 1 v+1
- 如果 v v v点存在没有访问的相邻节点且 v v v点不与 v + 1 v + 1 v+1点相连,此时必须将 v + 1 v + 1 v+1 连接到 v v v 上
- 如果 v v v 点所有相邻节点都被访问了, v + 1 v+1 v+1可以与 v v v相连,也可以和从 1 = > v 1 => v 1=>v中路径上的任意一点相连,路径上的点都在递归栈里面,此时可以让 v v v点退栈,一直回到某个满足条件 1 1 1 或 2 2 2的节点
- 如果第 3 3 3点的点退栈一直到起点 1 1 1号点都没有直接相连,说明存在不连通部分,此时必须加边,此时再去搜索不连通的部分,一直到全部搜索完
#include<bits/stdc++.h>
using namespace std;
const int N = 1e5 + 10;
int n, m, vis[N];
vector<int> e[N];
int ans, ne;
void dfs(int u)
{
ne ++;
for(int i = 0 ; i < e[u].size() ; i++)
{
int v = e[u][i];
if(vis[v]) continue;
if(v == ne)
{
vis[ne] = 1;
//cout << "case1:" << u << " " << v << " " << ne << '\n';
dfs(ne);
}else {
ans++;
vis[ne] = 1;
//cout << "case2:" << u << " " << v << " " << ne << '\n';
dfs(ne);
i--;//表示并没有使用u->v这条边 所以要重新看一次这条边
}
}
//如果遍历完了所有出边 最终走到了ne 但ne并不是n 说明并不联通 需要继续连边
if( u == 1 ){
while(ne <= n){
vis[ne] = 1;
//cout << "case3:" << u << " " << ne << '\n';
dfs(ne);
ans++;
}
}
}
void solve()
{
cin >> n >> m;
ans = 0, ne = 1;
for(int i = 1 ; i <= n ; i++)
{
e[i].clear();
vis[i] = 0;
}
for(int i = 0 ; i < m ; i++)
{
int a, b;
cin >> a >> b;
if(a > b) e[b].push_back(a);
else e[a].push_back(b);
}
for(int i = 1 ; i <= n ; i++)
sort(e[i].begin(), e[i].end());
vis[1] = 1;
dfs(1);
cout << ans << "\n";
}
int main()
{
ios::sync_with_stdio(false);
cin.tie(0),cout.tie(0);
int _;
cin >> _;
while(_--) solve();
return 0;
}