poj 4045 Power Station

题目可以在4044里面按problem下载pdf。

题目大意:
给你一颗树,求一个点,使树上所有点到该点的距离之和最小。

思路:
以该树任意一点s为起点,进行dfs,记录下以每个点x为根的 还未搜索到的子节点的个数numForRoot[x],和以该点为根,剩下的未搜到的子节点到该点的距离之和dp[x]。对于起点s来说,由于在此之前未访问任何节点,所以dp[s]代表所有点到s距离之和。
再进行一次dfs,同样以s为起点,对于当前节点now(now!=s) ,设其父节点为fa,g_n为总节点个数。
dp[now]=dp[fa]+(g_n-numForRoot[now])-numForRoot[now];
其实这个方程可以看成是将每个边将树分为两个部分,当点选在一边的时候,这条边就要被经过多少次。这样可能比较好理解吧。

#include
#include
#include
#include
#include
using namespace std;
#define Max 50009
int head[Max];
int vis[Max];
int res[Max];
int numForRoot[Max];
int g_outcnt;
long long dp[Max];
struct edgst
{
    int to;
    int next;
};
int g_cnt;
int g_n;
int root=1;
edgst edg[Max<<1];
int min(int a,int b)
{
    if(a>b) return b;
    else return a;
}

void add(int from,int to)
{
    edg[g_cnt].to=to;
    edg[g_cnt].next=head[from];
    head[from]=g_cnt++;
}

void dfs1(int now)
{
    vis[now]=1;
    numForRoot[now]=1;
    for(int e=head[now];e!=-1;e=edg[e].next)
    {
        int to = edg[e].to;
        if(!vis[to])
        {
            dfs1(to);
            numForRoot[now]+=numForRoot[to];
            dp[now]+=dp[to]+numForRoot[to];
        }
    }
}

void dfs2(int now,int fa)
{
    vis[now]=1;
    if(fa!=-1)
        dp[now]=dp[fa]+(g_n-2*numForRoot[now]);
    for(int e=head[now];e!=-1;e=edg[e].next)
    {
        int to = edg[e].to;
        if(!vis[to])
        {
            dfs2(to,now);
        }
    }
}

int main()
{
    int i,j,n,I,R;
    int a,b;
    int tes;
    long long ans;
    int ind;
    scanf("%d",&tes);
    while(tes--)
    {
        memset(head,-1,sizeof(head));
        memset(vis,0,sizeof(vis));
        memset(dp,0,sizeof(dp));
        g_cnt=0;

        scanf("%d%d%d",&n,&I,&R);
        g_n=n;
        for(i=1;idp[i])
            {
                ans=dp[i];
                g_outcnt=1;
                res[0]=i;
            }
            else if(ans==dp[i])
            {
                res[g_outcnt++]=i;
            }
        }

        sort(res,res+g_outcnt);
        cout<


你可能感兴趣的:(ACM,struct,ini)