HDU

来源:互联网 发布:caffe安装 编辑:程序博客网 时间:2024/06/14 00:23

HDU - 3245传送门


题意:有n(n<=10000)个点构成一个树,取树上一条长为L(L<=100)的路径(覆盖L+1个点),问树上所有点到这条路径的距离和的最小值。

分析:这道题最初,感觉不好下手,拖啦三天,才写出来。先随便找一点作为根把无根树转化为有根树。设d[x][l]表示从x根节点向下延伸l个点(包括x)的最大“节省距离”。(假设x有一根节点y,dp[x][2]延伸到y,那么节省距离就是,原本y子树的点到x为最近点,路径延伸到y,此时最近点为y,节省的距离就是y子树减小的距离和)。用dp维护这个值。在每个节点处枚举它的两个儿子形成的路径的最大“节省距离”。然后用所有点到该节点的距离减掉这个”节省距离“就是答案啦求出最小值就是答案啦。


#include<iostream>#include<cstdio>#include<cstring>#include<vector>#include<algorithm>using namespace std;typedef double LL;const int N=10100;const int INF=0x3f3f3f3f;int num[N],dp[N][2],d[N][111],dis[3][111];//dp[x][0]存的是x所有子节点到x的距离 dp[x][1]存的是x这个子树外的所有点到x点的距离。 int n,ans,k;                            vector<int> g[N];void dfs1(int x,int fa){    dp[x][0]=0;    num[x]=1;    for(int i=0;i<g[x].size();i++)    {        int y=g[x][i];        if(y==fa)continue;        dfs1(y,x);        num[x]+=num[y];        dp[x][0]+=(dp[y][0]+num[y]);    }}void dfs2(int x,int fa){    dp[x][1]=0;    if(fa!=-1)    {        dp[x][1]+=dp[fa][1];        dp[x][1]+=(dp[fa][0]-dp[x][0]-num[x]);        dp[x][1]+=(n-num[x]);    }    for(int i=0;i<g[x].size();i++)    {        int y=g[x][i];        if(y==fa)continue;        dfs2(y,x);    }}void dfs3(int x,int fa){    for(int i=0;i<g[x].size();i++)    {        int y=g[x][i];        if(y==fa)continue;        dfs3(y,x);        for(int j=2;j<=k;j++)         d[x][j]=max(d[x][j],d[y][j-1]+num[y]);    }    memset(dis,-0x3f,sizeof(dis));    dis[0][0]=0;    dis[1][0]=0;    dis[2][0]=0;    for(int i=0;i<g[x].size();i++)    {        int y=g[x][i];        if(y==fa)continue;        for(int ff=2;ff>=1;ff--)        {            for(int v=k-1;v>=0;v--)            for(int j=0;j<=v;j++)            {                dis[ff][v]=max(dis[ff][v],dis[ff-1][v-j]+d[y][j]+num[y]*min(1,j));            }        }    }    ans=min(ans,dp[x][0]+dp[x][1]-dis[2][k-1]);}int main(){    int x,y;    while(scanf("%d%d",&n,&k)!=EOF&&n)    {   k++;        if(n==1)        {            printf("0\n");            continue;        }              for(int i=0;i<n;i++)            g[i].clear();        memset(d,0,sizeof(d));        for(int i=1;i<n;i++)        {            scanf("%d%d",&x,&y);            g[x].push_back(y);            g[y].push_back(x);        }        ans=INF;        dfs1(0,-1);        dfs2(0,-1);        dfs3(0,-1);        printf("%d\n",ans);    }    return 0;}


原创粉丝点击