集训模拟赛-1-T1

Posted sktskyking

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了集训模拟赛-1-T1相关的知识,希望对你有一定的参考价值。

最近学校网课跟得紧没时间写知识点,就拿题解凑个数(bushi

而且前两天我打着打着题解电脑就突然死机 幸运的是 我没有保存(微笑)

废话不多说 上题目!

城市攻击
(city)
(256MB,1s)
【问题描述】
出于某些原因,A国将对B国进行攻击。B国有n个城市,有n-1
双向条道路,每条道路连接两个城市,任意两个城市可以通过道路
互相到达,即构成一棵树。由于资金有限,A国只能攻击B国的两个
城市,攻击后这两个城市将会毁灭,与这两个城市连接的道路也随
之消失,A国希望在攻击后能将B国分成尽可能多的连通块,这样有
利于A国的下一步行动,于是他们找到你来完成这个任务。
【输入格式】
输入文件名为city.in
第一行包含一个整数T,表示数据组数。
对于每组数据
第一行包含一个整数n,表示B国城市的数量。
接下来n-1行,每行两个整数x,y,表示有一条道路连接城市x与城市y
【输出格式】
输出文件名为city.out
输出文件包含T个整数,表示对于每组数据,攻击两个城市后最多能
使B国分成多少个连通块
【输入样例】
city.in city.out
2
5
1 2
2 4
3 4
4 5
7
1 2
2 3
1 4
1 5
3 6
3 7
3
5

【数据规模与约定】
对于20%的数据T<=5,1≤n≤100
对于50%的数据T<=5,1≤n≤1000
对于100%的数据T<=10,1≤n≤100000

看到这个题说实话我考试的时候二话不说直接爆搜= =

但后来老师一讲就发现其实有窍门

具体看我的详(la)细(ji)题解:

 1 //通过画图可以看出我们要通过删除度数最多的城市点来拆分连通块,在枚举过程中发现删除xy会得到d[x]+d[y]-n个连通块
 2 //且两点相连时n为2两点不连时n为1
 3 //max分别列举情况 判断即可 
 4 #include<cstdio>
 5 #include<cstdlib>
 6 #include<cstring>
 7 #include<iostream>
 8 using namespace std;
 9 struct node// 
10 {
11     int y,next;//y代表目标位, next的意义参照day3-例1 
12 }a[2000010];
13 int first[1000010],len;// first【x】从x出发的第一条边 
14 int d[1000010];//度数 
15 void ins(int x,int y)//边列表 
16 {
17     a[++len].y=y;
18     a[len].next=first[x];
19     first[x]=len;
20 }
21 bool is_conected(int x,int y)//判断两点之间有没有联系 
22 {
23     int k;
24     for(k=first[x];k;k=a[k].next)
25       if(a[k].y==y)return 1;
26     return 0;
27 }
28 int main()
29 {
30     freopen("city.in","r",stdin);
31     freopen("city.out","w",stdout);
32     int o,n,i,j,k,x,y;
33     scanf("%d",&o);//数据组数 
34     while(o--)
35     {
36       scanf("%d",&n);//B国城市数量 
37       for(i=1;i<=n;i++) first[i]=d[i]=0;//先全部清空一遍 
38       len=0;//清空 
39       for(i=1;i<n;i++)
40       {
41         scanf("%d%d",&x,&y);
42         ins(x,y);ins(y,x);//存储他们的边 因为是无向图 所以当做双向用 
43         d[x]++;d[y]++;//x,y的度数分别加1 
44       }
45       int max_d=0,sec_d=0;//max代指目前度数最大的点 sec代指度数第二大的点 _d代指这个度数的值 
46       int max_s=0,m1,m2;//max_s代表目前最大点的个数 m1记录第一个最大点的编号 m2代表第二个 当这两个点都有存储时代表有两个及以上,如果最大度数的点有三个及以上不用记录 一定有两个最大度数点不相连
47       int sec_s=0;//第二大度数的点的个数 
48       for(i=1;i<=n;i++)//记录最大度数的点的个数以及第二大度数的点的个数 
49       {
50         if(d[i]>max_d)//扫描到的点的度数如果比当前的最大的度数值要大 
51         {
52           sec_d=max_d;
53           sec_s=max_s;//当前的“最大”度数变成第二大,更新第二大的度数点的相关数据 
54           max_d=d[i];
55           max_s=1;m1=i;//更新最大度数点 m1更新 
56         }
57         else if(d[i]==max_d)
58         {
59           max_s++;//最大度数的点的个数+1 
60           if(max_s==2)m2=i;//m2更新 
61         }
62         else if(d[i]>sec_d)//更新第二大的度数代表的一系列数据 
63           sec_d=d[i],sec_s=1;
64         else if(d[i]==sec_d)
65           sec_s++;
66       }//如果又else 什么都不用做 
67       
68       if(max_s>=3){printf("%d
",2*max_d-1);continue;} 
69       if(max_s==2)
70       {
71         if(is_conected(m1,m2))//判断两点是否相连 
72         printf("%d
",2*max_d-2);
73         else printf("%d
",2*max_d-1);
74         continue;
75       }
76       //max_s=1;无需判断,直接操作 
77       int s=0;
78       for(k=first[m1];k;k=a[k].next)//扫描从x出发的第一条边开始 意为消除第一个城市然后确定连通块数量 
79       {
80         y=a[k].y;
81         if(d[y]==sec_d) s++;//这两步的意思是寻找与x相连的sec,s为计数点 
82       }
83       if(s==sec_s)//如果与max连接的点的数量与总的点的数量一样 
84       printf("%d
",max_d+sec_d-2);//出推论 
85       else printf("%d
",max_d+sec_d-1);//反之,出推论 
86     }
87     return 0;
88 }

好了大概就这么多

但是这个题没A,why?

 

 

 

因为!

 

 

 

 

我不会离散化(哭了)

好了如果你喜欢这篇题解别忘了点赞投币收藏……

诶?好像跑题了= =

 

以上是关于集训模拟赛-1-T1的主要内容,如果未能解决你的问题,请参考以下文章

7.8集训模拟赛(忘记板子)

集训之6-26模拟赛一

7.6集训模拟赛9(老姚出出出出出题怪辟的的一天)

国庆集训模拟赛总结

暑假集训贪心模拟赛

2017.11.26清华集训2017模拟