1. 程式人生 > >The 2018 ACM-ICPC CCPC寧夏 G-Factories(樹形dp+揹包)

The 2018 ACM-ICPC CCPC寧夏 G-Factories(樹形dp+揹包)

題目:給你n個城市,n-1條道路,每兩個城市僅有一條通路,即一個樹形結構。讓你選擇m個葉子節點建立工廠,使得最終任意兩個工廠之間距離的累加和最小。

思路:考慮點之間的關係很繁瑣,所以我想的是對於一條邊來說考慮經過了它多少次。dp[u][i]表示u節點為根的子樹上選擇了i個葉子節點,會經過u這個子樹的邊的權值和的最優值。轉移方程如下:

dp[u][i]=min( dp[u][i-j]+dp[v][j]+w*j*(m-j) ); v是u的子節點,w是u與v之間邊的權值,k*(m-k)表示的是這條邊會被經過的次數(j為從v這個樹上過來的葉節點數,m-j為其它地方選擇的葉節點數)

我特麼是智障啊,思路早就想對了,怎麼考慮都沒錯,一直wa,最後才發現結果需要輸出 " Case #%d: %lld\n " !!!!!!傻逼錯誤一直犯,還要注意freopen()!

#include <bits/stdc++.h>
using namespace std;
#define ll long long
#define inf 1e12
const int maxn=1e5+10;
struct node{
    int x;
    ll w;
    node(int _x,ll _w)
    {
        x=_x;
        w=_w;
    }
};
vector<node>a[maxn];
int n,t,m,siz[maxn];
ll dp[maxn][102];
void dfs(int u,int fa)
{
    if(a[u].size()==1)
    {
        dp[u][1]=0;
        siz[u]=1;///記錄葉節點數量
    }
    dp[u][0]=0;
    for(int i=0;i<a[u].size();i++)
    {
        int v=a[u][i].x;
        ll w=a[u][i].w;
        if(v==fa) continue;
        dfs(v,u);
        siz[u]+=siz[v];
        dp[u][m]=min(dp[v][m],dp[u][m]);///直接從v上選了m個葉子
        for(int j=min(m,siz[u]);j>=1;j--)
        {
            for(int k=1;k<=min(j,siz[v]);k++)
                dp[u][j]=min(dp[u][j],dp[u][j-k]+dp[v][k]+1ll*w*1ll*k*1ll*(m-k));//轉移方程
        }
    }
}
int main()
{
    ///freopen("in.txt","r",stdin);
    scanf("%d",&t);
    int cas=0;
    while(t--)
    {
        scanf("%d%d",&n,&m);
        for(int i=1;i<=n;i++)
            a[i].clear();
        for(int i=1;i<n;i++)
        {
            int x,y;
            ll w;
            scanf("%d%d%lld",&x,&y,&w);
            a[x].push_back(node(y,w));
            a[y].push_back(node(x,w));
        }

        memset(siz,0,sizeof siz);
        int rt=1;
        for(int i=1;i<=n;i++)//找到一個不為葉子的節點作為根
        if(a[i].size()>1)
        {
            rt=i;
            break;
        }
        for(int i=1;i<=n;i++)
        for(int j=1;j<=m;j++)
            dp[i][j]=inf;
        for(int i=1;i<=n;i++)
            dp[i][0]=0;
        dfs(rt,-1);
        printf("Case #%d: %lld\n",++cas,dp[rt][m]);
    }
    return 0;
}