• [题解] [JSOI2013] 旅行时的困惑


    题面

    题解

    首先我们要思考一个问题, 公交线路要加到什么程度才能够使得任意两个点两两可达
    很容易知道每个点和他的父亲必须两两可达
    所以最终所有公交线路新增的边其实就是把原来的边全部反向
    那么这些边要如何组成公交线路呢, 必须要满足, 在这条公交线路中, 边的指向相同, 要么都向上, 要么都向下, 或者原来向上, 在某个点转成向下, 也可以反过来
    我们既然要使得公交线路数最短, 就要使只向上的和只向下的路径长度尽量长, 并且要是更多的向上和向下的路径在某个点相交
    那么我们就可以得到这样一个贪心策略
    对于一个点, 我们先尽量让向上的和向下的相抵消, 那么最多一种会剩下来, 然后再看这一种和这个点向父亲连的边的方向是不是一样的
    如果是, 就把他传上去, 看能不能再跟其他的匹配
    如果不是, 那他传不了了, 就只能到这里打止
    这样一定是最优的, 如果你当前不把能匹配的匹配完了, 上去匹配的话, 可能没有可以和你匹配的
    但如果你在这里就匹配了的话, 公交线路数量至少不会变多
    所以这样是最优的

    Code

    #include <algorithm>
    #include <iostream>
    #include <cstring>
    #include <cstdio>
    const int N = 100005; 
    using namespace std;
    
    int n, st[N], ed[N], head[N], ans, g[N], up[N], down[N], cnt, dep[N], id[N];
    struct edge { int to, nxt; } e[N << 1]; 
    
    template < typename T >
    inline T read()
    {
        T x = 0, w = 1; char c = getchar();
        while(c < '0' || c > '9') { if(c == '-') w = -1; c = getchar(); }
        while(c >= '0' && c <= '9') x = x * 10 + c - '0', c = getchar();
        return x * w; 
    }
    
    inline void adde(int u, int v) { e[++cnt] = (edge) { v, head[u] }, head[u] = cnt; }
    
    void dfs1(int u, int fa)
    {
        dep[u] = dep[fa] + 1;
        for(int v, i = head[u]; i; i = e[i].nxt)
        {
    	v = e[i].to; if(v == fa) continue;
    	dfs1(v, u); 
        }
    }
    
    void dfs(int u, int fa)
    {
        for(int v, i = head[u]; i; i = e[i].nxt)
        {
    	v = e[i].to; if(v == fa) continue; 
    	dfs(v, u); id[v] == 1 ? down[u] += g[v] : up[u] += g[v]; 
        }
        int tmp = min(down[u], up[u]);
        ans += tmp, down[u] -= tmp, up[u] -= tmp;
        if(u == 1) ans += up[u] + down[u];
        else ans += id[u] == 1 ? up[u] : down[u]; 
        g[u] = max(1, id[u] == 1 ? down[u] : up[u]); 
    }
    
    int main()
    {
        n = read <int> ();
        for(int i = 1; i < n; i++)
        {
    	st[i] = read <int> () + 1, ed[i] = read <int> () + 1;
    	adde(st[i], ed[i]), adde(ed[i], st[i]); 
        }
        dfs1(1, 0);
        for(int i = 1; i < n; i++)
    	if(dep[st[i]] < dep[ed[i]])
    	    id[ed[i]] = 1; 
    	else id[st[i]] = 2; 
        dfs(1, 0);
        printf("%d
    ", ans); 
        return 0; 
    }
    
  • 相关阅读:
    用TPLINK 无线网卡设置无线工作环境
    ChartDirector与JFreeChart两款主要web图表工具调研报告
    发现奇怪的问题,TOMCAT居然跟本机网卡的DNS设置有关
    解决Oracle监听器服务不能启动的问题
    JAVA 调用 .NET写的WEBSERVICE
    Windows Forms 实现安全的多线程详解
    异步调用与多线程
    关于.NET异步调用的初步总结
    c#中的多线程同步
    WinForm界面开发
  • 原文地址:https://www.cnblogs.com/ztlztl/p/12289149.html
Copyright © 2020-2023  润新知