zoukankan      html  css  js  c++  java
  • @bzoj


    @description@

    你有一个无向连通图,边的总数为偶数。
    设图中有k个奇点(度数为奇数的点),你需要把它们配成k/2个点对(显然k被2整除)。对于每个点对(u,v),你需要用一条长度为偶数(假设每条边长度为1)的路径将u和v连接。每条路径允许经过重复的点,但不允许经过重复的边。这k/2条路径之间也不能有重复的边。

    原题链接。

    @solution@

    先不考虑路径长度必须为偶数,其实就是跑 k/2 条欧拉路径。
    这个实现方法很多,讲一种这道题可以用的:建虚点 s,s 向所有奇点连虚边,跑欧拉回路,然后断开所有虚边。

    考虑路径长度为偶数,联想到二分图。考虑一个点拆成黑白两点,原来的一条边 (u, v) 对应了 u 的黑/白点连向 v 的白/黑点。
    如果虚点 s 只向奇点的黑点连边,则跑出来的欧拉回路一定是路径长度为偶数。

    不过这个拆点中,一条边 (u, v) 只能对应 u 的黑/白点连向 v 的白/黑点中一种情况。
    所以我们要加以选择,使得建出来的新图中每个点的度数依然为偶数。
    因为白点度数 + 黑点度数 = 原图点度数,所以我们只需要白点度数为偶数即可。

    考虑将问题转化一下:给每条边 (u, v) 定向成 u -> v 或 v -> u,定向后每个点的出边即这个点白点连出去的边。
    这个问题就是经典问题了,建出任意一棵生成树(一般选 dfs 树)后,非树边随便选,树边自下而上调整,即可保证每个白点的度数为偶数。

    @accepted code@

    #include <cstdio>
    
    const int MAXN = 2*250000;
    
    struct Graph{
    	struct edge{
    		int to, id; bool tag;
    		edge *nxt, *rev;
    	}edges[2*MAXN + 5], *adj[MAXN + 5], *ecnt;
    	Graph() {ecnt = edges;}
    	void addedge(int u, int v, int i) {
    		edge *p = (++ecnt), *q = (++ecnt);
    		p->to = v, p->id = i, p->nxt = adj[u], adj[u] = p;
    		q->to = u, q->id = i, q->nxt = adj[v], adj[v] = q;
    		p->rev = q, q->rev = p;
    //		printf("! %d %d %d
    ", u, v, i);
    	}
    }G1, G2;
    #define rep(G, x) for(Graph::edge *p=G.adj[x];p;p=p->nxt)
    
    int dfn[MAXN + 5], oud[MAXN + 5], dcnt;
    void dfs(int x, int f) {
    	dfn[x] = (++dcnt);
    	rep(G1, x) {
    		if( p->to == f ) continue;
    		if( dfn[p->to] ) {
    			if( dfn[p->to] < dfn[x] )
    				G2.addedge(2*x, 2*p->to-1, p->id), oud[x]++;
    		}
    		else {
    			dfs(p->to, x);
    			if( oud[p->to] & 1 )
    				G2.addedge(2*p->to, 2*x-1, p->id), oud[p->to]++;
    			else G2.addedge(2*p->to-1, 2*x, p->id), oud[x]++;
    		}
    	}
    }
    
    Graph::edge *stk[MAXN + 5]; int tp;
    
    void dfs2(int x) {
    //	printf("! %d
    ", x);
    	for(;G2.adj[x];) {
    		Graph::edge *p = G2.adj[x]; G2.adj[x] = G2.adj[x]->nxt;
    		if( p->tag ) continue;
    		p->tag = p->rev->tag = true;
    		dfs2(p->to);
    		stk[++tp] = p->rev;
    	}
    }
    
    int deg[MAXN + 5];
    
    int main() {
    	int n, m; scanf("%d%d", &n, &m);
    	for(int i=1;i<=m;i++) {
    		int a, b; scanf("%d%d", &a, &b);
    		G1.addedge(a, b, i), deg[a]++, deg[b]++;
    	}
    	for(int i=1;i<=n;i++)
    		if( deg[i] & 1 ) G2.addedge(0, 2*i-1, -1);
    	dfs(1, -1), dfs2(0);
    	int lst = 1;
    /*
    	for(int i=1;i<=tp;i++)
    		printf("%d ", stk[i]->id);
    	puts("");
    */
    	for(int i=2;i<=tp;i++) {
    		if( stk[i]->id == -1 ) {
    			printf("%d %d %d
    ", (stk[lst]->to + 1)/2, (stk[i]->rev->to + 1)/2, i - lst - 1);
    			for(int j=lst+1;j<=i-1;j++) {
    				printf("%d%c", stk[j]->id, j + 1 == i ? '
    ' : ' ');
    			}
    			i++, lst = i;
    		}
    	}
    }
    

    @details@

    需要注意欧拉回路的实现,要用类当前弧优化的方法进行优化,不然时间复杂度不正确。

  • 相关阅读:
    在应用程序级别之外使用注册为 allowDefinition='MachineToApplication' 的节是错误的……
    VS 扩展管理器,方便的插件
    VUE CLI中使用Jquery无法获取到dom节点
    Navicat 连接SQL Server LocalDB的方法
    修改cas登陆页面服务器端
    easyui tree 拖拽功能并将数据返回后台保存至数据库
    RedHat下GCC及G++的安装
    Java中的字符串池
    Java内存泄露
    TSQL字符转义
  • 原文地址:https://www.cnblogs.com/Tiw-Air-OAO/p/12232698.html
Copyright © 2011-2022 走看看