【2021四川省赛补题】

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 wia i i i 距离 p p p 有多远。
1 ≤ w i ≤ 100 1 \leq w_i \leq 100 1wi100
多源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](jk)
关于输入输出的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 1n
思路:

  1. 如果 v v v v + 1 v + 1 v+1直接相连,则访问搜索 v + 1 v + 1 v+1
  2. 如果 v v v点存在没有访问的相邻节点且 v v v点不与 v + 1 v + 1 v+1点相连,此时必须将 v + 1 v + 1 v+1 连接到 v v v
  3. 如果 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的节点
  4. 如果第 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;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值