zoukankan      html  css  js  c++  java
  • [Codeforces 911F] Tree Destruction 解题报告(贪心)

    题目链接:

    http://codeforces.com/contest/911/problem/F

    题目大意:

    给你一棵树,每次挑选这棵树的两个度数为1的点,加上他们之间的边数(距离),然后将其中一个点去掉,问你边数(距离)之和最大可以是多少.

    要求输出每次选择的两个点和删掉的点

    题解:

    贪心题,策略是每次选择一个度数为1的点和距离它较远的直径的端点(显然直径的端点度数为1),然后把这个点删掉保留直径的端点。直到只剩下直径的时候才开始删掉直径上的点

    为什么?考虑到先删一个直径外的点再删直径的端点一定不会比删掉一个直径的端点再删这个点更劣(不妨画个图?)。

    应该还有这么个结论吧,距离任意一个点最远的叶子节点一定是直径的一个端点,感觉挺正确的

    #include<algorithm>
    #include<cstring>
    #include<cstdio>
    #include<iostream>
    #include<vector>
    #include<queue>
    using namespace std;
    typedef long long ll;
    
    const int N=2e5+15;
    int n;
    int d1[N],d2[N],deg[N],vis[N],a[N],b[N],c[N];
    vector <int> g[N];
    inline int read()
    {
        char ch=getchar();
        int s=0,f=1;
        while (ch<'0'||ch>'9') {if (ch=='-') f=-1;ch=getchar();}
        while (ch>='0'&&ch<='9') {s=(s<<3)+(s<<1)+ch-'0';ch=getchar();}
        return s*f;
    }
    void dfs(int x,int fa,int *d)
    {
        for (int i=0;i<g[x].size();i++)
        {
            int y=g[x][i];
            if (y==fa) continue;
            d[y]=d[x]+1;
            dfs(y,x,d);
        }
    }
    void out(int x,int fa,int goal)
    {
        for (int i=0;i<g[x].size();i++)
        {
            int y=g[x][i];
            if (vis[y]||y==fa) continue;
            printf("%d %d %d
    ",x,goal,x);
            out(y,x,goal);
        }
    }
    int main()
    {
        n=read();
        for (int i=1,u,v;i<n;i++)
        {
            u=read();v=read();
            g[u].push_back(v);g[v].push_back(u);
            deg[u]++;deg[v]++;
        }
        int p1,p2,mx=0;
        d1[1]=0;dfs(1,-1,d1);
        for (int i=1;i<=n;i++) if (d1[i]>mx) {mx=d1[i];p1=i;}
        d1[p1]=0;dfs(p1,-1,d1);
        mx=0;for (int i=1;i<=n;i++) if (d1[i]>mx) {mx=d1[i];p2=i;}
        d2[p2]=0;dfs(p2,-1,d2);
        queue<int> q;
        ll ans=0;
        int tot=0;
        for (int i=1;i<=n;i++) if (d1[i]+d2[i]!=d1[p2]&&deg[i]==1) q.push(i);
        while (!q.empty())
        {
            int k=q.front();q.pop();
            ans+=max(d1[k],d2[k]);
            a[++tot]=k;b[tot]=(d1[k]>d2[k])?p1:p2;c[tot]=k;vis[k]=1;
            for (int i=0;i<g[k].size();i++)
            {
                int y=g[k][i];
                if (vis[y]) continue;
                --deg[y];
                if (d1[y]+d2[y]!=d1[p2]&&deg[y]==1) q.push(y);
            }
        }
        ans+=1ll*(d1[p2]+1)*d1[p2]/2;
        printf("%lld
    ",ans);
        for (int i=1;i<=tot;i++) printf("%d %d %d
    ",a[i],b[i],c[i]);
        out(p1,-1,p2);
        return 0;
    }
  • 相关阅读:
    【HDOJ】2774 Shuffle
    【POJ】2170 Lattice Animals
    【POJ】1084 Square Destroyer
    【POJ】3523 The Morning after Halloween
    【POJ】3134 Power Calculus
    【Latex】如何在Latex中插入伪代码 —— clrscode3e
    【HDOJ】4801 Pocket Cube 的几种解法和优化
    【HDOJ】4080 Stammering Aliens
    【HDOJ】1800 Flying to the Mars
    SQL语法
  • 原文地址:https://www.cnblogs.com/xxzh/p/9764423.html
Copyright © 2011-2022 走看看