1. 程式人生 > 其它 >NOIP 模擬 $13\; \text{卡常題}$

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();}