• NOIP2018 旅行


    传送门

    题意:60pts:给定一棵树,从某一个点出发,允许沿着来的路径返回。每次访问新城市,将标号加入到序列中,求字典序最小的序列。
    另40pts:给定一棵基环树,从某一个点出发,允许沿着来的路径返回。每次访问新城市,将标号加入到序列中,求字典序最小的序列。

    首先任何情况下都要先从1出发。
    树的部分很好解决,每次从所在节点的子节点中选出最小的,并遍历其子树。
    基环树的部分,可以发现这个环一定不会每条边都走,因此暴力枚举哪条边不走即可。注意判断删边之后的连通性
    n=5000可过

    using namespace std;
    const int MAXN = 5005;
    const int MAXM = 5005;
    
    int n, m, num;
    int ban;
    int fir[MAXN], nxt[MAXM << 1], to[MAXM << 1], cnt;
    int vis[MAXN];
    int ans[MAXN], now[MAXN];
    int son[MAXN][MAXN];
    
    struct Edge{
    	int a, b;
    }e[MAXM];
    
    inline int read(){
    	int k = 0, f = 1; char ch = getchar();
    	while(ch < '0' || ch > '9'){if(ch == '-') f = -1; ch = getchar();}
    	while(ch >= '0' && ch <= '9'){k = k * 10 + ch - '0'; ch = getchar();}
    	return k * f;
    }
    
    inline void add_edge(int a, int b){
    	to[cnt] = b; nxt[cnt] = fir[a]; fir[a] = cnt++;
    }
    
    void dfs(int u, int f){
    	now[++num] = u;
    	vis[u] = true;
    	for(int i = fir[u]; i != -1; i = nxt[i]){
    		int v = to[i];
    		if(vis[v]) continue;
    		if(e[ban].a == u && e[ban].b == v) continue;
    		if(e[ban].a == v && e[ban].b == u) continue;
    		son[u][++son[u][0]] = v;
    	}
    	sort(son[u] + 1, son[u] + son[u][0] + 1);
    	for(int i = 1; i <= son[u][0]; i++){
    		dfs(son[u][i], u);
    	}
    }
    
    int main(){
    	memset(fir, -1, sizeof(fir)); cnt = 0;
    	n = read(), m = read();
    	for(int i = 1; i <= m; i++){
    		int a = read(), b = read();
    		e[i] = (Edge){a, b};
    		add_edge(a, b);
    		add_edge(b, a);
    	}
    	
    	
    	if(m == n - 1){
    		dfs(1, 0);
    		for(int j = 1; j <= n; j++){
    			ans[j] = now[j];
    		}
    	}
    	else{
    		ans[1] = 1e9;
    		for(int i = 1; i <= n; i++){
    			num = 0;
    			memset(vis, 0, sizeof(vis));
    			ban = i;
    			
    			for(int j = 1; j <= n; j++) son[j][0] = 0;
    			
    			dfs(1, 0);
    			
    			if(num < n) continue;
    			
    			for(int j = 1; j <= n; j++){
    				if(now[j] > ans[j]) break;
    				
    				if(now[j] < ans[j]){
    					for(int k = 1; k <= n; k++){
    						ans[k] = now[k];
    					}
    					break;
    				}
    			}
    		}
    	}
    	
    	for(int i = 1; i <= n; i++){
    		printf("%d ", ans[i]);
    	}
    	
    	return 0;
    }```
  • 相关阅读:
    删除文件夹
    遍历文件夹
    二分查找
    轻松记住大端小端的含义(附对大端和小端的解释)
    Motorola和Intel格式报文解析的区别
    Intel格式与Motorola格式的区别
    ADC采样工作原理详解
    软件概要设计做什么
    共模干扰和差模干扰
    什么是GPIO?
  • 原文地址:https://www.cnblogs.com/asdf1229/p/14548710.html
Copyright © 2020-2023  润新知