题意:给你一棵无向树,让你求以某个点为根,其他所有点到根节点的路径和最小,答案等于这个路径和*I*I*R,如果有多个路径和最小的点,输出所有的点。
1 这题题目只要输出T组,开始以为多case,以EOF结束,wa了几发。
2 注意答案可能超int,所有得用__int64或者long long 。
3 每组样例得输出一个空行。
dp[i]表示以i节点为根的路径和。
num[i]表示以i节点为根的节点数和。
dfs1()
dp[i]=dp[j]+num[j];
num[i]=sum(num[j])+1
dfs2()
dp[j]=dp[j]+(dp[i]-dp[j]-num[j])+(num[i]-num[j]); 画图理解下,其实就是通过父节点求子节点路径和。
代码:
#include<iostream> #include<vector> #include<string> #include<queue> #include<map> #include<cstdio> #include<cstring> #define maxn 50005 #define INF 0x1fffffffffffffff #define ll long long using namespace std; int cnt,N; int head[maxn],vis[maxn]; ll dp[maxn],num[maxn]; vector<int> g; struct e { int to,next; } edg[maxn*2]; void init() { cnt=0; memset(head,-1,sizeof(head)); memset(dp,0,sizeof(dp)); memset(num,0,sizeof(dp)); memset(vis,0,sizeof(vis)); g.clear(); } void add(int from,int to) { edg[cnt].to=to; edg[cnt].next=head[from]; head[from]=cnt++; } void dfs1(int u)//求出以任意点为根的dp[],num[] { vis[u]=1; num[u]=1; dp[u]=0; int v; for(int i=head[u]; i!=-1; i=edg[i].next) { v=edg[i].to; if(vis[v]==0) { dfs1(v); num[u]+=num[v]; dp[u]+=(dp[v]+num[v]); } } } void dfs2(int u) { vis[u]=1; int i,v; for(i=head[u]; i!=-1; i=edg[i].next) { v=edg[i].to; if(vis[v]==0) { dp[v]=dp[u]+N-2*num[v]; dfs2(v); } } } int main() { int t,I,R,i,j,k,a,b; scanf("%d",&t); while(t--) { init(); scanf("%d%d%d",&N,&I,&R); for(i=1; i<N; i++) { scanf("%d%d",&a,&b); add(a,b); add(b,a); } //num[i]记录以i为子树根节点的节点数,dp[i]记录以i为组数根节点到其他所有点的路径之和 //vector<>记录所有最大值的点 dfs1(1); for(i=1; i<=N; i++) { if(dp[i]<result) { g.clear(); g.push_back(i); result =dp[i]; } else if(dp[i]==result) { g.push_back(i); } } printf("%lld\n",result*I*I*R); int size=g.size(); for(i=0; i<size; i++) { printf("%d",g[i]); printf("%c",i==size-1?'\n':' '); } printf("\n"); } return 0; }