zoukankan      html  css  js  c++  java
  • 【LG5022】[NOIP2018]旅行

    【LG5022】[NOIP2018]旅行

    题面

    洛谷

    题解

    首先考虑一棵树的部分分怎么打

    直接从根节点开始(dfs),依次选择编号最小的儿子即可

    而此题是一个基环树

    怎么办呢?

    可以断掉环上的一条边,这样就变为一棵树了

    再用上面的方法做即可

    (tips) (:)

    断环上的边,其实可以直接用(tarjan)把桥求出来

    不是桥的就是环上的边

    考场上的代码有点乱

    #include <iostream>
    #include <cstdio>
    #include <cstdlib>
    #include <cstring>
    #include <cmath>
    #include <algorithm>
    #include <vector> 
    using namespace std;
    inline int gi() {
    	register int data = 0, w = 1; 
    	register char ch = 0;
    	while (ch != '-' && !isdigit(ch)) ch = getchar(); 
    	if (ch == '-') w = -1, ch = getchar();
    	while (isdigit(ch)) data = data * 10 + ch - '0', ch = getchar();
    	return w * data; 
    }
    #define MAX_N 5005
    vector<int> G[MAX_N];
    struct Graph { int to, next; } e[MAX_N << 1]; int fir[MAX_N], e_cnt; 
    void clearGraph(){ memset(fir, -1, sizeof(fir)); } 
    void Add_Edge(int u, int v) { e[e_cnt] = (Graph){v, fir[u]}; fir[u] = e_cnt++; }
    struct Edge { 
    	int to, id;
    	bool operator < (const Edge &rhs) const { return to < rhs.to; } 
    } ; 
    vector<Edge> rG[MAX_N]; 
    int N, M; 
    namespace cpp1 {
    	void dfs(int x, int f) {
    		printf("%d ", x); 
    		for (int i = 0, sz = rG[x].size(); i < sz; i++) {
    			int v = rG[x][i].to;
    			if (v == f) continue;
    			dfs(v, x); 
    		} 
    	} 
    	void main() { dfs(1, 0); putchar('
    '); } 
    }
    
    namespace cpp2 {
    	int dfn[MAX_N], low[MAX_N], tim; 
    	bool bridge[MAX_N << 1];
    	void tarjan(int x, int id) {
    		dfn[x] = low[x] = ++tim;
    		for (int i = fir[x]; ~i; i = e[i].next) {
    			int v = e[i].to;
    			if (!dfn[v]) {
    				tarjan(v, i), low[x] = min(low[x], low[v]); 
    				if (low[v] > dfn[x]) bridge[i] = bridge[i ^ 1] = 1; 
    			} else if (i != (id ^ 1)) low[x] = min(low[x], dfn[v]); 
    		} 
    	}
    	int ans[MAX_N], tmp[MAX_N], cnt;
    	bool used[MAX_N << 1]; 
    	void dfs(int x, int fa) {
    		tmp[++cnt] = x;
    		for (int i = 0, sz = rG[x].size(); i < sz; i++) {
    			int v = rG[x][i].to, id = rG[x][i].id;
    			if (v == fa || used[id]) continue;
    			dfs(v, x); 
    		} 
    	} 
    	bool check() {
    		for (int i = 1; i <= N; i++) {
    			if (ans[i] > tmp[i]) return 1;
    			else if (ans[i] < tmp[i]) return 0; 
    		} 
    		return 0; 
    	} 
        void main() { 
    		tarjan(1, -1);
    		for (int i = 1; i <= N; i++) ans[i] = N + 1;
    		for (int i = 0; i < e_cnt; i += 2) {
    			if (bridge[i]) continue; 
    			used[i] = used[i ^ 1] = 1; cnt = 0;
    			dfs(1, 0);
    			if (check()) for (int j = 1; j <= N; j++) ans[j] = tmp[j]; 
    			used[i] = used[i ^ 1] = 0; 
    		}
    		for (int i = 1; i <= N; i++) printf("%d ", ans[i]);
    		putchar('
    '); 
    	} 
    } 
    bool used[MAX_N][MAX_N]; 
    int main () {
    	N = gi(), M = gi(); 
    	for (int i = 1; i <= M; i++) {
    		int u = gi(), v = gi();
    		G[u].push_back(v), G[v].push_back(u); 
    	} 
    	for (int i = 1; i <= N; i++) sort(G[i].begin(), G[i].end());
    	clearGraph(); 
    	for (int i = 1; i <= N; i++)
    		for (int j = G[i].size() - 1; j >= 0; j--) {
    			int v = G[i][j]; if (used[i][v]) continue; 
    			Add_Edge(i, v), Add_Edge(v, i); 
    			used[i][v] = used[v][i] = 1; 
    		} 
    	for (int x = 1; x <= N; x++) {
    		for (int i = fir[x]; ~i; i = e[i].next) {
    			int v = e[i].to;
    			rG[x].push_back((Edge){v, i}); 
    		} 
    	}
    	for (int i = 1; i <= N; i++) sort(rG[i].begin(), rG[i].end()); 
    	if (N - 1 == M) cpp1::main(); 
    	else cpp2::main(); 
    	return 0; 
    } 
    
  • 相关阅读:
    开发了套三维光学扫描仪,可以技术转让
    见微知著 带你透过内存看 Slice 和 Array的异同
    Goland 这些技巧,学会开发效率翻倍!
    不懂汇编,也能看懂的 Go interface 原理分析
    win10创建删除文件文件夹需刷新才更新问题
    转载:java中DAO层、Service层、Control层的说明
    代码习惯
    查看网站的服务器和使用的技术
    flutter: CSS规则映射flutter控件-position
    android对话框透传Touch事件
  • 原文地址:https://www.cnblogs.com/heyujun/p/9979481.html
Copyright © 2011-2022 走看看