zoukankan      html  css  js  c++  java
  • UVa 10859

    题目

    https://uva.onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&page=show_problem&problem=1800


    题意

    n(n < 1000)个节点m条边的无向无环无重边图,最小顶点覆盖的同时要尽量让只有一个端点是点亮的边数最少

    思路

    如刘书:

    1. 无向无环图一定是森林,适用树形DP

    2. 因为有两个优化目标,所以将两个目标线性组合,设以i为根的树上的顶点覆盖数为x,单点点亮边数为y,由于y < 1000,所以可以这样组合,令M>1000,优化目标为xM + y,此处M不妨取2e3

    3. 通常情况下树形DP只考虑当前节点i的点亮状态和i节点到子节点的关系,但这样就需要在x最小的同时,选取一部分子节点亮让y最小,由于子节点的数量可能较多,点亮的方法也有多种,这使得统计单点点亮边数变成了比较复杂的事情。刘书则记录i节点的父节点的点亮状态,这样,统计单点点亮边数时,统计的是i到父亲这一条是不是单点点亮,而不是i到儿子这若干条是不是,更为方便。

    4. 令a[i]为当i的父亲节点点亮时,以i为根的子树满足题意所需的最小综合代价,b为不点亮时代价。那么,明显,令suma为子节点a之和,sumb为子节点b之和

    统计a[i]时,由于父亲节点已经点亮,i可以选择点亮或者不点亮。令singleEdgeSupp为父节点点亮而i不点亮的代价,当i为根时singleEdgeSupp=0,否则为1.a[i] = min(mina + M, minb + singleEdgeSupp),

    统计b[i]时,只能点亮i,b[i] = mina + M + 1

    假设这颗树真正的根节点为root,那么答案很明显是a[root],因为可以认为根节点有个虚拟父节点,虚拟父节点是点亮的。

    感想

    1. 错误地认为边<=1就是叶节点,忽略了根节点只有1个或者没有叶结点的情况。

    2. 当只有根节点一个点时,按照Debug上所说的,不需要点灯

    代码

    #include <algorithm>
    #include <cassert>
    #include <cmath>
    #include <cstdio>
    #include <cstring>
    #include <iostream>
    #include <map>
    #include <queue>
    #include <set>
    #include <string>
    #include <tuple>
    #define LOCAL_DEBUG
    using namespace std;
    typedef pair<int, int> MyPair;
    int n, m;
    const int MAXN = 1e3 + 3;
    const int M = 2e3;
    const int INF = 0x7ffffff;
    int edges[MAXN][MAXN];
    int edgeCnt[MAXN];
    int a[MAXN];//father is lighted up
    int b[MAXN];//isn't
    bool vis[MAXN];
    
    void dfs(int f, int fa) {
        vis[f] = true;
        if (edgeCnt[f] <= 1 && fa != -1) {
            a[f] = 1;
            b[f] = M + 1;
        }
        else {
            int singleEdgeSupp = (fa == -1 ? 0 : 1);
            int suma = 0;//light up itself
            int sumb = 0;//do not light up
            for (int i = 0; i < edgeCnt[f]; i++) {
                int t = edges[f][i];
                if (t == fa)continue;
                dfs(t, f);
                suma += a[t];
                sumb += b[t];
            }
            a[f] = min(suma + M, sumb + singleEdgeSupp);
            b[f] = suma + singleEdgeSupp + M;
        }
    }
    
    int main() {
    #ifdef LOCAL_DEBUG
        freopen("C:\Users\Iris\source\repos\ACM\ACM\input.txt", "r", stdin);
        freopen("C:\Users\Iris\source\repos\ACM\ACM\output.txt", "w", stdout);
    #endif // LOCAL_DEBUG
        int T;
        scanf("%d", &T);
        for (int ti = 1; ti <= T && scanf("%d%d", &n, &m) == 2; ti++) {
            memset(edgeCnt, 0, sizeof(edgeCnt));
            memset(vis, 0, sizeof(vis));
            for (int i = 0; i < m; i++) {
                int f, t;
                scanf("%d%d", &f, &t);
                edges[f][edgeCnt[f]++] = t;
                edges[t][edgeCnt[t]++] = f;
            }
            int ansNode = 0;
            int ansSingleEdge = 0;
            for (int i = 0; i < n; i++) {
                if (!vis[i]) {
                    dfs(i, -1);
                    int sta = a[i];
                    /*if (sta == 0) {
                        sta = M;
                    }*/
                    ansNode += sta / M;
                    ansSingleEdge += sta % M;
                }
            }
            printf("%d %d %d
    ", ansNode, m - ansSingleEdge, ansSingleEdge);
    
    
        }
    
        return 0;
    }
    View Code
  • 相关阅读:
    No module named _tkinter
    Camera2与TextureView使用
    Collections常用方法总结
    Android插件化框架
    《战狼2》观后感——民族荣耀
    《茶马古道》观后感——朝圣之路
    点击查看大图Activity
    图片压缩代码
    《天那边》观后感——对一些现象的反思
    recyclerView的使用
  • 原文地址:https://www.cnblogs.com/xuesu/p/10456392.html
Copyright © 2011-2022 走看看