题目连接: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; }