D. 爱好和平 2014新生暑假个人排位赛06
题目描述
在星际时代,每个帝国都靠着贸易路线连接着各个联盟星球,这些贸易路线都是双向可达的。一个帝国的综合实力由他贸易连接着的联盟星球数决定。
学姐作为Mays帝国的领袖,长期与Luke帝国保持着敌对关系,爱好和平的学姐希望结束长达几个世纪的战争,于是找实验室定做了一颗代号小苹果的炸弹,可以定点摧毁一颗星球,这颗星球被毁后,与它相连的全部贸易就都被切断了,这样Luke帝国可能就被切断为一个小联盟,他们就再也不会对学姐的地位构成威胁啦~
经过调查,Luke帝国为了节约经费,他的联盟星之间都有且仅有一条直接或间接的贸易通路。
现在给出Luke帝国的贸易线路,学姐想知道摧毁哪一颗行星可以使得分裂后的若干Luke联盟威胁最大的分部最小。
输入格式
输入有多组数据,组数不大于10组。每一组开头一行为n,m,表示Luke帝国的联盟星球数量,和贸易关系数,接下来m行,每行两个整数u,v,表示星球u,v之间存在直接的贸易路线,1<=u,v<=n,1<=n,m<=100000
输出格式
输出一个数表示推荐学姐摧毁的星球,如果有多解,输出编号最小的一个。
输入样例
5 4
1 2
1 3
1 4
4 5
输出样例
1
赛中提交:NULL
赛后AC:YES (T T T WA WA WA AC)
题目大意:
给n个点和m个边,并且“联盟星之间都有且仅有一条直接或间接的贸易通路”
也就是说“点与点之间都有且仅有一条直接或间接的路径”
也就是说不会成环,是一个无向无环图,可以看做是一棵树
然后要求拿走哪一个点之后,剩下的子树的最大值最小
思路:
树状DP
任选一个点只来一遍DFS,
DFS函数返回值是“不包括他的当前前驱节点在内的所有子孙(注意是子孙所有后代)的个数”
在DFS过程中通过先求出排除他的当前前驱节点后的最大子树mostw[i],然后对比这个最大子树和n-mostw[i]
得出的值就是真正的最大子树,赋给mostw[i]
最后再在main中取mostw[i]的最小值
反省:
这道题会卡vector的常数倍时间,通过这道题学会了手写邻接链表
#include <iostream>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <string>
#include <vector>
#include <list>
#include <map>
#include <queue>
#include <stack>
#include <bitset>
#include <algorithm>
#include <numeric>
#include <functional>
#define maxn 100005
#define maxe 200005
using namespace std;
int si,head[maxn];
int totalson[maxn],used[maxn],mostw[maxn];
struct edge{int to,next;}G[maxe];
bool flag;
void add_edge(int u,int v)
{
G[si].to=v;
G[si].next=head[u];
head[u]=si++;
}
int dfs(int fa,int fafa)
{
if(used[fa]==true){
flag=false;
return 0;
}
used[fa]=true;
int s,son,ans=0;
int tmp=0,sum=0;
for(int i=head[fa];i!=-1;i=G[i].next){
int son=G[i].to;
if(son!=fafa){
tmp=dfs(son,fa);
ans=max(ans,tmp);
sum+=tmp;
}
}
mostw[fa]=ans; //该节点所有子孙的最大值
totalson[fa]=sum+1; //该节点所有子孙与其自身的个数总和
return sum+1;
}
int main()
{
int n,m;
while(scanf("%d %d",&n,&m)!=EOF){
int u,v;
memset(head,-1,sizeof(head));
memset(totalson,0,sizeof(totalson));
memset(mostw,0,sizeof(mostw));
si=0;
flag=true;
for(int i=0;i<m;i++){
scanf("%d %d",&u,&v);
add_edge(u,v);
add_edge(v,u);
}
memset(used,0,sizeof(used));
dfs(1,0);
for(int i=1;i<=n;i+=1){
mostw[i]=max(mostw[i],n-totalson[i]);
}
int maxp=999999999,ans=-1;
for(int i=1;i<=n;i+=1){
if(maxp>mostw[i]){
maxp=mostw[i];
ans=i;
}
}
printf("%d\n",ans);
}
return 0;
}