题目连接:http://acm.hdu.edu.cn/showproblem.php?pid=3899

题意:吉林大学有n个学院,有n-1条路保证这n个学院两两相连,现在要举行一场程序设计大赛,问在哪一个学院举行,所需的花费最少。

在第i个学院举行所需的花费为sum(dis(i,j)*num[j]) ,(1=<j <= n);

dis(i,j)表示第j个学院与第i个学院之间的距离,num[j]表示第j个学院有少个支队伍参赛!

由于n<=100000就限制了不能暴力枚举!

很明显的树形DP,先算出在第1个学院举行时所需的总花费。以第1个学院为根可以建一棵树,然后求出每个节点的Num值。

这个Num值包括该节点以及该节点的所有子孙节点的num值。

每个节点所需的总花费存在数组DP里面,那么DP[v]=DP[u]+(sum-Num[v])*edge[j].val+Num[v]*edge[j].val;

u是v的父亲节点,sum表示所有参赛队伍。

这样一深搜一光搜就ok了。

但是hdu存在爆栈的问题。。深搜需要手动模拟,很蛋疼。。结果写出来了虽然AC了,但跑了2000+ms;

看了别人的解题报告,发现可以预处理设置栈的内存大小,改了之后200ms+;

#pragma comment(linker, "/STACK:1024000000,1024000000")

预处理栈大小。后面的数字应该是可以根据具体的情况修改吧。

贴下手动模拟栈的吧:

# include<stdio.h>
# include<string.h>
# include<stack>
# include<queue>
# define N 100005
using namespace std;
int num[N];
struct node{
    int from,to,next,val;
}edge[2*N];
int head[N],tol,vis[N];
__int64 DP[N],Min,Num[N],sum,dis[N];
stack<int>S;
queue<int>S1;
void add(int a,int b,int c)
{
    edge[tol].from=a;edge[tol].to=b;edge[tol].val=c;edge[tol].next=head[a];head[a]=tol++;
}
void dfs()
{
    int j,v,u;
    S.push(1);
    while(!S.empty())
    {
        u=S.top();
        vis[u]=1;
        for(j=head[u];j!=-1;j=edge[j].next)
        {
            v=edge[j].to;
            if(vis[v]) continue;
            dis[v]=dis[u]+edge[j].val;
            Min+=dis[v]*num[v];
            S.push(v);
            break;
        }
        if(j==-1)
        {
            Num[u]=num[u];
            for(j=head[u];j!=-1;j=edge[j].next)
            {
                v=edge[j].to;
                Num[u]+=Num[v];
            }
            S.pop();
        }
    }
}
/*void DFS()
{
    int j,v,u;
    S.push(1);
    while(!S.empty())
    {
        u=S.top();
        vis[u]=1;
        for(j=head[u];j!=-1;j=edge[j].next)
        {
            v=edge[j].to;
            if(vis[v]) continue;
            DP[v]=DP[u]+(sum-Num[v]-Num[v])*edge[j].val;
            S.push(v);
            break;
        }
        if(j==-1) S.pop();
    }
}*/
void bfs()
{
    int j,u,v;
    S1.push(1);
    vis[1]=1;
    while(!S1.empty())
    {
        u=S1.front();
        S1.pop();
        for(j=head[u];j!=-1;j=edge[j].next)
        {
            v=edge[j].to;
            if(vis[v]) continue;
            DP[v]=DP[u]+(sum-Num[v]*2)*edge[j].val;
            S1.push(v);
            vis[v]=1;
        }
    }
}
int main()
{
    int i,n,a,b,c;
    while(scanf("%d",&n)!=EOF)
    {
        sum=0;
        for(i=1;i<=n;i++)
        {
            scanf("%d",&num[i]);
            sum+=num[i];
        }
        tol=0;
        memset(head,-1,sizeof(head));
        for(i=1;i<n;i++)
        {
            scanf("%d%d%d",&a,&b,&c);
            add(a,b,c);
            add(b,a,c);
        }
        Min=0;
        memset(vis,0,sizeof(vis));
        memset(Num,0,sizeof(Num));
        dis[1]=0;
        dfs();//先求出在college 1举办时所需的最少花费
        DP[1]=Min;
        memset(vis,0,sizeof(vis));
        bfs();
        for(i=1;i<=n;i++)
            if(DP[i]<Min) Min=DP[i];
            printf("%I64d\n",Min);
    }
    return 0;
}

 

posted on 2011-10-09 16:24  奋斗青春  阅读(535)  评论(0编辑  收藏  举报