zoukankan      html  css  js  c++  java
  • 8.30 巫师之旅

    题意

    给出一张(n)个点(m)条边的无向图,定义一次旅行为任选一个点(x)作为起点,再走到一个与(x)直接连接的点(y),再走到一个与(y)直接连接的点(z)结束本次旅行

    要求每条边(无向边)只能被经过一次,而点没有限制

    请计算出可能进行的最多的旅游次数并输出其中任意一种方案


    解法

    这题考试时想出来了,但打得代码又臭又长。。

    可以玩一玩,发现对于一个连通块,它的答案就是其中的边数除以(2)

    本题的难点在于方案的输出

    考虑对于一颗树,我们怎样输出方案

    可以规定合并的顺序为先儿子,后父亲

    即如果该点有儿子,则把儿子两两进行合并;如果该点有奇数个儿子,则把最后一个儿子与父亲合并并打上标记

    这样一定能构造出一个合法的方案,因为每一个结点一定是由它的父亲进行更新的

    考虑更复杂的情况,即原题所要求的图

    我们可以发现图其实就是树的情况拉上了很多条非树边

    非树边可以与儿子放在一起,规则同上

    这样就能构造出一个合法解了


    代码

    就不放考场上打得(3kb)奇丑无比的代码了。。

    #include <cstdio>
    #include <queue>
    #include <cstring>
    
    using namespace std;
    
    const int N = 4e5 + 10;
    
    int n, m;
    
    int cap = 1;
    int head[N], to[N << 1], nxt[N << 1];
    
    int cnt, num;
    int bfn[N], fa[N], can[N], ans[N][3];
    
    int book[N], vis[N];
    
    queue<int> que;
    
    inline void add(int x, int y) {
    	to[++cap] = y, nxt[cap] = head[x], head[x] = cap;
    }
    
    void init(int rt) {
    	cnt = 0;
    	que.push(rt), book[rt] = 1;
    	while (!que.empty()) {
    		int x = que.front(); que.pop();
    		bfn[++cnt] = x;
    		for (int i = head[x]; i; i = nxt[i]) {
    			if (book[to[i]])	continue;
    			que.push(to[i]);
    			fa[to[i]] = x, book[to[i]] = 1;
    		}
    	}	
    }
    
    void solve(int rt) {
    	init(rt);
    	for (int i = cnt; i >= 1; --i) {
    		int x = bfn[i], tot = 0;
    		for (int j = head[x]; j; j = nxt[j]) 
    			if (!vis[j] && to[j] != fa[x])	can[++tot] = j;
    		for (int j = head[x]; j; j = nxt[j])
    			if (!vis[j] && to[j] == fa[x])	can[++tot] = j;
    		for (int j = 1; j + 1 <= tot; ++j) {
                vis[can[j]] = vis[can[j] ^ 1] = 1;
                ans[++num][0] = to[can[j]];
                ++j;
                ans[num][1] = x;
                vis[can[j]] = vis[can[j] ^ 1] = 1;
                ans[num][2] = to[can[j]];
            }
    	}
    }
    
    int main() {
    	
    	scanf("%d%d", &n, &m);
    	
    	int u, v;
    	for (int i = 1; i <= m; ++i) {
    		scanf("%d%d", &u, &v);
    		add(u, v), add(v, u);
    	}
    	
    	for (int i = 1; i <= n; ++i) 
    		if (!book[i])	solve(i);	
    	
    	printf("%d
    ", num);
    	for (int i = 1; i <= num; ++i)	printf("%d %d %d
    ", ans[i][0], ans[i][1], ans[i][2]);
    	
    	return 0;
    }
    
  • 相关阅读:
    [HNOI2008] Cards
    loj #136
    a problem
    dp * 3
    STL
    套题1
    luogu 4211
    loj #2319
    loj #2316
    luogu 1144
  • 原文地址:https://www.cnblogs.com/VeniVidiVici/p/11436338.html
Copyright © 2011-2022 走看看