zoukankan      html  css  js  c++  java
  • P5663 加工零件 题解

    CSDN同步

    原题链接

    简要题意:

    给定一个图,每次询问从 (x) 节点开始,(y) 步能不能达到 (1) 号节点。

    算法一

    这也是我本人考场算法。就是 深搜

    因为你会发现,如果 (x)(y \% 2) 步能到 (1) 节点,那肯定 (y) 步能到。

    原因是:剩下的 (y - y \% 2) 是偶数,只要重复走一条边多次即可。

    我们用 (f_{i,0/1}) 表示,从 (i) 号节点经过 偶数步(0) 奇数步(1) 能到 (1) 号节点的最短步数。

    (1) 开始深搜即可。如果已有答案当前答案更优,则结束。

    时间复杂度:(O(n^2)).(代码后会解释)

    实际得分:(80pts).(考场上也就这么多)

    #pragma GCC optimize(2)
    #include<bits/stdc++.h>
    using namespace std;
    
    const int N=1e5+1;
    
    inline int read(){char ch=getchar();int f=1;while(ch<'0' || ch>'9') {if(ch=='-') f=-f; ch=getchar();}
    	int x=0;while(ch>='0' && ch<='9') x=(x<<3)+(x<<1)+ch-'0',ch=getchar();return x*f;}
    
    int f[N][2];
    int n,m,q;
    vector<int>G[N];
    
    inline void dfs(int dep,int bs) {
    	if(f[dep][bs%2]!=-1 && f[dep][bs%2]<=bs) return; //无需更新答案
    	f[dep][bs%2]=bs; //记录答案
    	for(int i=0;i<G[dep].size();i++) {
    		int x=G[dep][i];
    		dfs(G[dep][i],bs+1);
    	}
    }
    
    int main(){
    	n=read(),m=read(),q=read();
    	memset(f,-1,sizeof(f));
    	while(m--) {
    		int x=read(),y=read();
    		G[x].push_back(y);
    		G[y].push_back(x);
    	} f[1][0]=2; dfs(1,0);
    	while(q--) {
    		int x=read(),y=read();
    		if(f[x][y%2]!=-1 && f[x][y%2]<=y) puts("Yes");
    		else puts("No");
    	} //判断
    	return 0;
    }
    
    

    你会说,这个程序的时间复杂度是 (O(n)) 吧?怎么是 (O(n^2))

    这个问题也困扰了我很久,以至于很难想清楚,怎样的一种情况可以卡掉它。

    重写了代码之后就发现了。

    因为,如果是个完全图的话,每个点都会被其它点到达(尽管被 ( exttt{return}) 但还是做了),所以是 (O(n^2)).

    你会说,那也不会是完全图啊?(n)(m) 是同阶啊?

    也对。所以完全图不用考虑,给定图肯定是稀疏图。

    那么,问题在哪儿?

    你想,如果原图是一个长 (10^5) 的一个环。

    此时,这个程序极有可能炸掉。

    因为,如果你的遍历顺序一路走完了这个环,然后又走一遍(因为奇偶性不同,导致走 (2) 次)。

    接着,里面的每个点的探索次数为 (2),也就是说每个点又开始向其它点探索。

    但是,假设你在第三次走环的时候 (1) 结束掉,此时 (n) 号节点就返到 (n-1) 号节点。

    然后 (n-1) 号节点的递归次数就变成 (2),它把锅都甩给了两边,又到了 (n),然后才结束。

    每个点都把自己身上的锅(就是递归次数)扔给相邻的,但是,你必须要走 (n) 次(就到头) 才可以确定一个节点的答案。

    此时 (O(n^2)).

    那么,如何优化这个程序呢?

    算法二

    深搜不行,用宽搜。

    用了宽搜就不存在 “互相甩锅” 这个问题。每个人只会甩常数次锅。

    时间复杂度:(O(n+m)).((n) 有系数,但被忽略)

    实际得分:(100pts).

    #pragma GCC optimize(2)
    #include<bits/stdc++.h>
    using namespace std;
    
    const int N=1e5+1;
    
    inline int read(){char ch=getchar();int f=1;while(ch<'0' || ch>'9') {if(ch=='-') f=-f; ch=getchar();}
    	int x=0;while(ch>='0' && ch<='9') x=(x<<3)+(x<<1)+ch-'0',ch=getchar();return x*f;}
    
    int f[N][2];
    int n,m,q;
    vector<int>G[N];
    
    inline void bfs() {
    	queue<pair<int,int> >q;
    	memset(f,0x3f,sizeof(f));
    	for(int i=0;i<G[1].size();i++) {
    		f[G[1][i]][1]=1; //与1相邻的点,奇数步能到达1
    		q.push(make_pair(G[1][i],1)); //入队
    	} while(!q.empty()) {
    		int x=q.front().first,y=q.front().second;
    		q.pop();
    		for(int i=0;i<G[x].size();i++) {
    			int k=G[x][i];
    			if(y+1<f[k][1-y%2]) {
    				f[k][1-y%2]=y+1;
    				q.push(make_pair(k,y+1)); //入队
    			} //1-y%2,就是 (y+1)%2,改变奇偶性后 0->1,1->0,正好用 1 减掉。
    		}
    	}
    }
    
    int main(){
    	n=read(),m=read(),q=read();
    	while(m--) {
    		int x=read(),y=read();
    		G[x].push_back(y);
    		G[y].push_back(x);
    	} bfs();
    	while(q--) {
    		int x=read(),y=read();
    		if(f[x][y%2]<=y) puts("Yes");
    		else puts("No");
    	}
    	return 0;
    }
    
    

    后记

    这个题目说明几点:

    • 宽搜不一定旁边要开哈希。

    • 深搜有的时候难以处理极大环。

  • 相关阅读:
    关于python Tk中实时的输出.
    tkinter调取签名网而设计签名页面(十七)
    多进程Multiprocessing模块
    tkinter做一个简单的登陆页面(十六)
    maven常用命令
    通用接口测试用例
    关于log4j
    场景测试-支付场景
    自动化测试的意义
    自动化测试之明确目的
  • 原文地址:https://www.cnblogs.com/bifanwen/p/12593318.html
Copyright © 2011-2022 走看看