• Bzoj 2443: [Usaco2011 Open]奇数度数


    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

    思路:

      一开始并没有什么好思路,和suika讨论了一下发现可以拽一颗DFS树出来进行树形DP。因为是无向图,所以保证DFS树不会出现横叉边

    所以DP思路就很显然了,首先叶子结点的边不能砍掉。对于每个非叶子结点,如果它儿子带来的边的个数为奇数,那就需要把它和它父亲之间

    的边砍掉。否则不能砍。最后在DFS树上留下的边就是答案需要的边。这样的话如果可以找到一个解。正确性是显然的。可是怎么证明这样找

    不到解就一定没有解呢。那...我就不知道了。。。

    // luogu-judger-enable-o2
    #include <cstdio>
    #include <algorithm>
    #include <cstring>
    #include <iostream>
    #include <queue>
    using namespace std;
    const int N = 51000, M = 210000;
    int head[N], to[M] ,nxt[M], cnt=1, idx[M];
    int dfn[N], rt[N], tot;
    bool dont[M];
    bool vis[M];
    void add(int a,int b,int c) {
        to[++cnt] = b;
        nxt[cnt]  = head[a];
        head[a] = cnt;
        idx[cnt] = c;
        
        to[++cnt] = a;
        nxt[cnt]  = head[b];
        head[b] = cnt;
        idx[cnt] = c;
    }
    bool dfs(int p, int f) {
        int siz=0;
        dfn[p]=dfn[f]+1;
        for(int i=head[p];i;i=nxt[i]) {
            if(to[i]!=f&&!dfn[to[i]]) {
                if(dfs(to[i], p))
                    dont[idx[i]] = 1;
                else {
                    siz++;
                    vis[idx[i]] = 1;
                }
            }
        }
        return siz%2;
    }
    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);
            add(a, b, i);
        }
        for(int i=1;i<=n;i++)
            if(!dfn[i])    
                if(!dfs(i, 0)) {
                    puts("-1");return 0;
                }
        int ans=0;
        for(int i=1;i<=m;i++) {
            if(!dont[i]&&vis[i]) ans++;
        } 
        printf("%d
    ",ans);
        for(int i=1;i<=m;i++) {
            if(!dont[i]&&vis[i]) printf("%d
    ",i);
        } 
    }
    
  • 相关阅读:
    用Latex编辑数学公式
    《利用Python进行数据分析》学习笔记之Matplotlib : pandas中的绘图函数
    《利用Python进行数据分析》学习笔记之Pandas基础
    splice()使用
    markdown语法
    【Docker】Docker 镜像
    【Docker】Docker 命令
    【Docker】Docker 安装
    【Docker】Docker 简介
    【MySQL 高级】知识拓展
  • 原文地址:https://www.cnblogs.com/Tobichi/p/9184655.html
Copyright © 2020-2023  润新知