Loading

NOIP 模拟 $13\; \text{卡常题}$

题解

一道环套树的最小点覆盖题目,所谓环套树就是有在 \(n\) 个点 \(n\) 条边的无向联通图中存在一个环

我们可以发现其去掉一条环上的边后就是一棵树

那么对于此题,我们把所有 \(x\) 方点当点 \(y\) 方点当边,随便找一条环上的边删掉,然后分别从此边的两个端点做树形 \(dp\)

对于一条边上的两个点,我们一定要选一个,但不需要都选,类似例题

所以方程很好推,\(dp_{i,0}\) 表示不选 \(i\) 后覆盖 \(i\) 子树的最小费用,\(dp_{i,0}\) 表示选 \(i\) 后覆盖 \(i\) 子树的最小费用

\[dp_{x,0}=\sum_v^{v\in son_x}dp_{v,1} \]

\[dp_{x,1}=\sum_v^{v\in son_x}\min(dp_{v,0},dp_{v,1}) \]

最后取两个端点中值最小的,因为我们也要覆盖被断开的边,所以端点必须要选取一个

Code
#include<bits/stdc++.h>
#define ri register signed
#define p(i) ++i
using namespace std;
namespace IO{
    char buf[1<<21],*p1=buf,*p2=buf;
    #define gc() p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<21,stdin),p1==p2)?EOF:*p1++
    template<typename T>inline void read(T &x) {
        ri f=1;x=0;register char ch=gc();
        while(ch<'0'||ch>'9') {if (ch=='-') f=0;ch=gc();}
        while(ch>='0'&&ch<='9') {x=(x<<1)+(x<<3)+(ch^48);ch=gc();}
        x=f?x:-x;
    }
}
using IO::read;
namespace nanfeng{
    #define cmax(x,y) ((x)>(y)?(x):(y))
    #define cmin(x,y) ((x)>(y)?(y):(x))
    #define FI FILE *IN
    #define FO FILE *OUT
    static const int N=1e6+7;
    int dp[N][2],first[N],cst[N],vis[N],bk1,bk2,t=1,n,a,b;
    struct edge{int v,nxt;}e[N<<1];
    inline void add(int u,int v) {
        e[t].v=v,e[t].nxt=first[u],first[u]=t++;
        e[t].v=u,e[t].nxt=first[v],first[v]=t++;
    }
    void dfs_pre(int x,int fa) {
        if (vis[x]) {bk1=x,bk2=fa;return;}
        vis[x]=1;
        for (ri i(first[x]),v;i;i=e[i].nxt) {
            if ((v=e[i].v)==fa) continue;
            dfs_pre(v,x);
        }
    }
    void dfs(int x,int fa) {
        dp[x][0]=0,dp[x][1]=cst[x];
        for (ri i(first[x]),v;i;i=e[i].nxt) {
            if ((v=e[i].v)==fa||x==bk1&&v==bk2||x==bk2&&v==bk1) continue;
            dfs(v,x);
            dp[x][0]+=dp[v][1];
            dp[x][1]+=cmin(dp[v][1],dp[v][0]);
        }
    }
    inline int main() {
        // FI=freopen("nanfeng.in","r",stdin);
        // FO=freopen("nanfeng.out","w",stdout);
        read(n),read(a),read(b);
        for (ri i(1),v1,v2;i<=n;p(i)) {
            read(v1),read(v2);
            cst[v1]+=a,cst[v2]+=b;
            add(v1,v2);
        }
        dfs_pre(1,0),dfs(bk1,0);
        ri tmp=dp[bk1][1];
        dfs(bk2,0);
        tmp=cmin(tmp,dp[bk2][1]);
        printf("%d\n",tmp);
        return 0;
    } 
}
int main() {return nanfeng::main();}
posted @ 2021-07-13 15:04  ナンカエデ  阅读(45)  评论(0编辑  收藏  举报