1. 程式人生 > >「Luogu P3931」SAC E#1 - 一道難題 Tree 解題報告

「Luogu P3931」SAC E#1 - 一道難題 Tree 解題報告

原題面

我環顧四周,發現大佬們的寫法都好高階!

比較差勁的我,只能交上一份DFS的題解

思路:

DFS(當然了,其他演算法也行)

要想切斷葉子節點根節點的連線

就是在葉子節點根節點之間砍掉一條邊

這明顯就很符合DFS的性質,一條路一直走下去,遇到分枝就分開走

於是我們DFS每一條路徑,然後求答案

複雜度為O(n)

但是——還沒完!

我們可以發現DFS有三種情況

1、該節點為葉子節點,此時只能刪去連線它和父節點的邊

2、該節點為枝節點,有父節點和子節點,需要選擇性的刪除

3、該節點為根節點,只有子節點,只能刪去連線它和子節點的邊

Code:

#include<bits/stdc++.h>
#define INF 0x7f7f7f7f
using namespace std;
struct node{
    int to,cost;
    int nxt;
    node(int a,int b):to(a),cost(b){    }
    node(){ }
}b[200010];
int n,t,r;
int head[100010];
int read()
{
    int s=0;
    char c=getchar();
    while(!isdigit(c))
        c=getchar();
    while(isdigit(c))
    {
        s=(s<<1)+(s<<3)+c-'0';
        c=getchar();
    }
    return s;
}
void add(int x,int y,int cost)//建邊
{
    b[++t]=node(y,cost);
    b[t].nxt=head[x];
    head[x]=t;
    b[++t]=node(x,cost);
    b[t].nxt=head[y];
    head[y]=t;
    return;
}
int Get(int k,int in)
{
    int i;
    int res=0;
    for(i=head[k];i;i=b[i].nxt)
        if(i!=(in^1))//成對變換原理,異或值相同但方向相反的邊為一組,避免重複
            res+=Get(b[i].to,i);
    if(!b[head[k]].nxt&&k!=r)//確定是葉子節點
        res=b[in].cost;
    else
        res=min(res,b[in].cost);//否則兩種方法選其一
    return res;
}
int main()
{
    int i;
    int x,y,cost;
    n=read();r=read();
    t=1;//初始賦1,利於成對變換
    for(i=1;i<n;i++)
    {
        x=read();y=read();cost=read();
        add(x,y,cost);
    }
    b[0].cost=INF;//對於根節點的雙重保險,防止出什麼岔子,比如結果為0
    printf("%d",Get(r,0));
    return 0;
}