BZOJ_2443_[Usaco2011 Open]奇数度数 _并查集+树形DP

BZOJ_2443_[Usaco2011 Open]奇数度数 _并查集、

Description

奶牛们遭到了进攻!在他们的共和国里,有N(1 <= N <=50,000)个城市,由M(1 <= M <= 100,000)条无向的道路连
接城市A_i和B_i(1 <= A_i <= N;1 <= B_i <= N;A_i != B_i; 不会有重复的道路出现)。然而,整个共和国不一定
是连通的——有一些城市无法到达另外一些城市。入侵者想得到共和国的地图。(入侵者很傻,因此,他们的绘制
地图的方法是去访问每一条边,T_T)。奶牛想要折磨一下入侵者,使得他们尽可能难地完成地图绘制。因此,奶牛
会破坏若干条道路。请你帮助奶牛找到一个道路的子集,使得每条边每个点的度数为奇数。或者输出不存在这样的
一个子集。(奶牛的图论学得真好.= =||)举个例子,考虑下面的共和国:
1---2
/
  3---4
如果我们保留道路1-3,2-3和3-4,破坏道路1-2,那么城市1,2,4都只有一条边相连,城市3有3条边相连:
1   2
/
  3---4

Input

* 第一行:两个用空格隔开的整数:N和M
* 第二行到M+1行:第i+1行有两个空格隔开的整数A_i和

Output

* 第一行: 一个整数表示需要保留的道路数量
* 第二到K+1行:每行一个数表示保留的道路的编号,范围是1...M。

Sample Input

4 4
1 2
2 3
3 1
3 4

Sample Output

3
2
3
4

直接说结论:任意拽出一棵生成树,把非树边扔掉,再在树的内部树形DP判断是否有解。
证明一下:对于一条非树边<u,v>,如果可能的构造法包含它,我们可以让<u,v>路径上所有边更改选择状态从而不选这条边,路径上的点的奇偶性不变。
然后并查集维护一下即可。
 
代码:
#include <cstdio>
#include <cstring>
#include <algorithm>
#define N 50050
#define M 100050
using namespace std;
inline char nc() {
    static char buf[100000],*p1,*p2;
    return p1==p2&&(p2=(p1=buf)+fread(buf,1,100000,stdin),p1==p2)?EOF:*p1++;
}
int rd() {
    int x=0; char s=nc();
    while(s<'0'||s>'9') s=nc();
    while(s>='0'&&s<='9') x=(x<<3)+(x<<1)+s-'0',s=nc();
    return x;
}
char pbuf[100000],*pp=pbuf;
void push(const char c) {
    if(pp-pbuf==100000) fwrite(pbuf,1,100000,stdout),pp=pbuf;
    *pp++=c;
}
void write(int x) {
    static int sta[35];
    int top=0;
    do{sta[top++]=x%10,x/=10;}while(x);
    while(top) push(sta[--top]+'0');
}
int head[N],to[N<<1],nxt[N<<1],val[N<<1],cnt;
int is[M],tot,n,m,fa[N],f[N],vis[N];
int find(int x) {return fa[x]==x?x:fa[x]=find(fa[x]);}
void add(int u,int v,int w) {
    to[++cnt]=v; nxt[cnt]=head[u]; head[u]=cnt; val[cnt]=w;
}
void dfs(int x,int y) {
    int i,now=0; vis[x]=1;
    for(i=head[x];i;i=nxt[i]) {
        if(to[i]!=y) {
            dfs(to[i],x);
            if(f[to[i]]) now++;
            else is[val[i]]=1,tot--;
        }
    }
    f[x]=!(now&1);
}
int main() {
    n=rd(); m=rd(); tot=m;
    register int i,x,y;
    for(i=1;i<=n;i++) fa[i]=i;
    for(i=1;i<=m;i++) {
        x=rd(); y=rd();
        int dx=find(x),dy=find(y);
        if(dx!=dy) add(x,y,i),add(y,x,i),fa[dx]=dy;
        else is[i]=1,tot--;
    }
    for(i=1;i<=n;i++) {
        if(!vis[i]) {
            dfs(i,0); if(f[i]) {puts("-1"); return 0;}
        }
    }
    write(tot); push('
');
    for(i=1;i<=m;i++) if(!is[i]) write(i),push('
');
    fwrite(pbuf,1,pp-pbuf,stdout);
}
原文地址:https://www.cnblogs.com/suika/p/9219573.html