树形DP

来源:互联网 发布:谈谈对网络借贷的认识 编辑:程序博客网 时间:2024/05/22 04:41


一个各种例题的博客点击打开链接

s

Holiday's Accommodation

HDU - 4118

#include<iostream>#include<iomanip>#include<string>#include<algorithm>#include<map>#include<set>#include<list>#include<queue>#include<vector>#include<stack>#include<cstdio>#include<cstdlib>#include<cmath>#include<cstring>using namespace std;typedef long long ll;typedef long double lb;typedef pair<int,int> pii;const int inf= 0x3f3f3f3f;const double eps= 1e-8;const int maxn = 200000+10;//之所以用ll是为了不爆int;ll dp[maxn];//是用来存这个点 某一边有多少个点;ll res;//结果bool mark[maxn];//用来标记,访问过就不要再访问了,防止倒回去;vector<pair<int,int> >v[maxn];int n;ll MIN(ll a,ll b){    return a<b?a:b;}void dfs(int id,int w,int num){    dp[id]=0;    mark[id]=true;    int sz=v[id].size();    for(int i=0;i<sz;i++)    {        int b=v[id][i].first;        int c=v[id][i].second;        if(mark[b]) continue;        dfs(b,c,num);        dp[id]+=dp[b];    }    dp[id]++;    res+=MIN(dp[id],n-dp[id])*w*2;//这一步就是核心了,就是一定能找到    //一种构造使得这条边左边的点到右边去,右边的点到左边去,当然如果做有点数不想等,就按少的算,总不可能挤一个坑;    //因为是又进去的又出去的,所以这条边被用了两遍;    //这个结果一定是最优的,至于为什么,因为无法在多用这条边2次了;}int main(){    int T;    scanf("%d",&T);    int cnt=0;    while(T--)    {        cnt++;        scanf("%d",&n);        for(int i=1;i<=n;i++)            v[i].clear();        memset(mark,false,sizeof(mark));        res=0;        for(int i=1;i<n;i++)        {            int a,b,c;            scanf("%d%d%d",&a,&b,&c);            v[a].push_back(make_pair(b,c));            v[b].push_back(make_pair(a,c));        }        dfs(1,0,n);        cout<<"Case #"<<cnt<<": "<<res<<endl;    }    return 0;}


原创粉丝点击