博客园 首页 私信博主 显示目录 隐藏目录 管理

P3931 SAC E#1 - 一道难题 Tree

P3931 SAC E#1 - 一道难题 Tree

2017-10-07


题目背景

冴月麟和魏潇承是好朋友。


题目描述

冴月麟为了守护幻想乡,而制造了幻想乡的倒影,将真实的幻想乡封印了。任何人都无法进入真实的幻想乡了,但是她给前来救她的魏潇承留了一个线索。

她设置了一棵树(有根)。树的每一条边上具有割掉该边的代价。

魏潇承需要计算出割开这棵树的最小代价,这就是冴月麟和魏潇承约定的小秘密。

帮帮魏潇承吧。

注:所谓割开一棵有根树,就是删除若干条边,使得任何任何叶子节点和根节点不连通。


输入输出格式

输入格式: 

输入第一行两个整数n,S表示树的节点个数和根。

接下来n-1行每行三个整数a、b、c,表示a、b之间有一条代价为c的边。

输出格式:

输出包含一行,一个整数,表示所求最小代价。

 


输入输出样例

输入样例#1:
4 1
1 2 1 
1 3 1
1 4 1
输出样例#1:
3
输入样例#2:
4 1
1 2 3
2 3 1
3 4 2
输出样例#2:
1

说明

对于20%的数据,n <= 10

对于50%的数据,n <= 1000

对于100%的数据,n <= 100000


这个题太可怕了,还是普及组的题目...x

 

dp比暴力还好想.暴力是我过后看题解后才发现可以这样做的x
我们用dp[i]表示让i以及以i为根节点的子树合法所要的最小贡献.
特殊的,每一个叶子节点的权值为INT
暴力转移qwq
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<algorithm>
#define ll long long
using namespace std;
const int maxn=100000+2333;
const int INT=1e9+7;
inline int read(){
    int an=0,f=1;
    char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
    while('0'<=ch&&ch<='9'){an=an*10+ch-'0';ch=getchar();}
    return an*f;
}
int f[maxn],cnt;
int dp[maxn];
bool vis[maxn];
struct saber{
int nex,to,wi;
}b[maxn<<1];
int root,n,in[maxn];
inline void add(int x,int y,int z){
    cnt++;
    b[cnt].to=y;
    b[cnt].nex=f[x];
    b[cnt].wi=z;
    f[x]=cnt;
}
void dfs(int x){
    vis[x]=1;
    if(in[x]!=1)dp[x]=0;
    for(int i=f[x];i;i=b[i].nex){
        int v=b[i].to;
        if(!vis[v]){
        dfs(v);
        dp[x]+=min(dp[v],b[i].wi);
        }
    }
}
int main(){
    n=read();root=read();
    for(int i=1;i<n;i++){
        int x=read(),y=read(),z=read();
        add(x,y,z);
        add(y,x,z);
        in[x]++;in[y]++;
    }
    for(int i=1;i<=n;++i)dp[i]=INT;
    dp[root]=0;
    dfs(root);
    cout<<dp[root];
    return 0;
}
一道难题 Tree

by:s_a_b_e_r

 

posted @ 2017-12-10 20:56  ck666  阅读(161)  评论(0编辑  收藏  举报