第四集,聚集城市
在小A解读完手机信息后,得到了特工们的位置情报以及他们最近将会又一次聚会(除了谈论了关于抓捕小A和小C的事情外,主要谈论了关于走私事情…)
因为小C原本是他们的内部人员,所以她知道这个组织有一个习惯,即特工们每次选择聚会的城市,他们都会选择使所有组员所在市距离聚会城市的路程的和最小的城市,而且每个城市最多有一名特工。
现在,小A知道了特工们的所在位置,小A根据城市地图绘制了一副简易图,图的如下信息:
1,有一副n个节点的双向无环图,每个节点表示一个城市。
2,每条边默认距离为1。
3,有m个城市里住了他们的组员。
根据这些信息,得出一个城市编号X(1<=X<=n),使X到这m个城市的距离的和最小。
小A知道这是他反击的机会,他需要证据,他不想在和小C一直过着颠簸流离的逃亡生活。他需要获取更多关于走私的信息,他才有足够多的证据端了这个组织.因此,他必须找到这个聚会城市、
有多组测试案例
第一行输入两个正整数n和m。(2<n<=10000,1<m<=n)
第二行接下来输入m个正整数mi,表示城市mi有1名特工(mi!=mj,i!=j)、
接下来有n-1行,每一行输入两个正整数a和b,表示城市a和城市b相连、
对于每组测试案例,输出符合的城市编号,如果有多个城市符合要求,则输出编号最小的那个城市、
8 4
4 3 6 7
4 7
5 6
1 8
1 3
7 5
5 2
5 3
5
思路:先以1或任意节点为根节点深度优先搜索计算出根结点到所有需要到达点的距离,并且用数组cot[]记录各个点为根节点的子树有多少个含有所需要到达点的数量。
再次进行深搜更新dp[] 状态转移方程dp[to]=dp[now]+m-2*cot[to]
最后遍历一遍数组dp[]寻找最大值出现的位置即可
#include<cstdio>
#include<cstring>
#include<vector>
using namespace std;
const int maxn = +;
vector<int>e[maxn];
int has[maxn],vis[maxn],minLen[maxn],cot[maxn],dp[maxn],n,m,num;
//has:记录哪几个城市需要到达
//vis:记录是否有搜索过
//minLen:记录1到所有需要到达城市的最小距离
//cot:记录儿子有多少个需要到达的城市 //初始化
void init()
{
memset(vis,,sizeof(vis));
memset(has,,sizeof(has));
memset(cot,,sizeof(cot));
memset(minLen,,sizeof(minLen));
memset(dp,,sizeof(dp));
for(int i= ; i<=n; i++)
e[i].clear();
} //计算最短长度和每个点儿子有多少个需要到达的城市
int dfs1(int now,int dep)
{
int temp=;
if(has[now])
temp=;
minLen[now]=dep;
int len=e[now].size();
for(int i=; i<len; i++)
{
int to =e[now][i];
if(!vis[to])
{
vis[to]=;
temp=temp+dfs1(to,dep+);
}
}
cot[now]=temp;
return temp;
} void dfs2(int now)
{
int len=e[now].size();
for(int i=; i<len; i++)
{
int to = e[now][i];
if(!vis[to])
{
vis[to]=;
dp[to]=dp[now]+m-*cot[to];//状态转移方程
//dp[to] = dp[now] + m-cot[to](离父节点的所有城市+1) -cot[to](离子节点的所有城市-1);
dfs2(to);
}
}
} int main()
{
while(~scanf("%d%d",&n,&m))
{
init();
for(int i = ; i<m; i++)
{
scanf("%d",&num);
has[num]=;
}
for(int i = ; i <n-; i++)
{
int x,y;
scanf("%d%d",&x,&y);
e[x].push_back(y);
e[y].push_back(x);
}
vis[]=;
dfs1(,);
for(int i=; i<=n; i++)
{
if(has[i])
dp[]+=minLen[i];
}
memset(vis,,sizeof(vis));
vis[]=;
dfs2();
int Min_dp=dp[],lie=;
for(int i=; i<=n; i++)
if(dp[i]<Min_dp)
{
Min_dp=dp[i];
lie=i;
}
printf("%d\n",lie);
}
return ;
}