【模拟题(63550802...)】解题报告【贪心】【拓扑排序】【找规律】【树相关】

目录:

  1、A【树相关】    2、B【找规律】    3、C【贪心】【拓扑排序】



A、

描述(A 输入文件 : A.input 输出文件 : A.output)
一个城市的构成是一颗n 个节点的树(2 ≤ n ≤ 200), 现在需要在树中找出两条不相交的路
径(即两条路径不能有重边也不能有重点),使得路径的长度的乘积最大。
输入描述
第一行一个数n 表示这个城市一共有 n 个节点。
接下来 n-1 行,每行两个数ai 和bi (1 ≤ ai,bi ≤ n ),分别表示从ai 到bi,有一条边,每条边
的长度为1。
输出描述
输出一行一个数表示两条路径长度最大的乘积。
样例数据
样例输入1:
7
1 2
1 3
1 4
1 5
1 6
1 7
样例输出1:
0
样例输入2:
6
1 2
2 3
2 4
5 4
6 4
样例输出2:
4



B、

描述(B 输入文件 : B.input 输出文件 : B.output)
有n 个人需要看医生, 其中第i 个人需要看医生的次数是ai, 一开始从1 到n 依次排列组成
一个等待队伍, 每个人依次看医生, 那么每个人看完医生有两种情况, 第一种情况:他
已经看够他需要看医生的次数,那么他会离开。第二种情况:他还需要看医生,那么他就
会选择重新站在队伍的最后。选择医生想知道,当他看过k 次病人之后,这个等待队伍是
什么样。
输入描述
第一行两个正整数 n 和 k (1 ≤ n ≤ 105, 0 ≤ k ≤ 1014)
第二行一共个n 正整数 a1, a2, ..., an (1 ≤ ai ≤ 109),用空格隔开。
输出描述
一行,按队列的顺序输出需要的结果,每两个数之间用空格隔开,注意不要输出多余的空
格。数据保证此时队列里至少有一个人。
样例数据
样例输入1:
3 3
1 2 1
样例输出1:
2
样例输入2:
7 10
1 3 3 1 2 3 1
样例输出2:6 2 3



C、

描述(C 输入文件 : C.input 输出文件 : C.output)
有n 个任务需要你去完成,这些任务分布在3 个不同的房间,编号为1,2,3, 其中有些任务
必须在一些其他的任务完成之后才能完成。现在知道完成一个任务需要1 的时间,现在知
从房间1 到2,2 到3,3 到1 需要1 的时间,从1 到3,2 到1,3 到2 需要2 的时间。现
在你可以选择你一开始的房间,问完全所有任务的最短时间是多少,保证可以完成。
输入描述
第一行一个数 n (1 ≤ n ≤ 200) 。
第二行 n 个数, 第i 个数 ci (1 ≤ ci ≤ 3) 表示该任务所在的房间。.
接下来一共 n 行. 第 i 行的第一个数是 ki (0 ≤ ki ≤ n - 1),表示完成第i 个任务之前需要完
成的任务个数,之后 ki 个正整数表示需要提前完成的任务的编号。
输出描述
输出一个正整数表示完成任务需要是时间。
样例数据
样例输入1:
5
2 2 1 1 3
1 5
2 5 1
2 5 4
1 5
0
样例输出1:
7



解题报告:

  第一题:先拿到到这道题的时候就想,这又是关于树的,没仔细想,肯定做不出来,就跳过写第二题了。结果后来写了这道题还得了70分,用了两个搜索回溯,找了所有边所以T了三组。正解:枚举边,以边的左右两点的子树找直径。什么是树的直径?就是这棵树的最长的一条路径。怎么搜?先从这个点出发找一条最长的路径,再从这条路径到的点搜一条最长的路径便是。所以有两个bfs,两个点就是4个dfs。要注意第二次dfs的时候不要越过所枚举的边的点找到另一棵子树上了。

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<cstring>
 4 #include<algorithm>
 5 using namespace std;
 6 const int maxn=205;
 7 int n,ans,a1,now;
 8 struct node{
 9     int l,r;
10 };
11 int tot,he[maxn],ne[maxn*2],to[maxn*2];
12 node bian[maxn];
13 void add(int a,int b)
14 {
15     tot++;
16     to[tot]=b;
17     ne[tot]=he[a];
18     he[a]=tot;
19 }
20 void dfs1(int x,int fa,int len)
21 {
22     for (int i=he[x];i;i=ne[i])
23       if (to[i]!=fa)
24         dfs1(to[i],x,len+1);
25     if (len>=a1) a1=len;
26     if (len==a1) now=x;
27 }
28 void dfs2(int x,int fa,int len,int cant)//find the longest road
29 {
30     for (int i=he[x];i;i=ne[i])
31       if (to[i]!=fa&&to[i]!=cant)
32         dfs2(to[i],x,len+1,cant);
33     if (len>=a1) a1=len;
34 }
35 int do_it(int x,int fa)
36 {
37     a1=0;now=0;
38     dfs1(x,fa,0);
39     dfs2(now,fa,0,fa);
40     return a1;
41 }
42 int main()
43 {
44     freopen("A.input","r",stdin);
45     freopen("A.output","w",stdout);
46     cin>>n;
47     for (int i=1;i<n;i++)
48         {
49             scanf("%d%d",&bian[i].l,&bian[i].r);
50             add(bian[i].l,bian[i].r);
51             add(bian[i].r,bian[i].l);
52         }
53     for (int i=1;i<n;i++)
54         ans=max(ans,do_it(bian[i].l,bian[i].r)*do_it(bian[i].r,bian[i].l));
55     cout<<ans;
56     return 0;
57 }



  第二题:先开始看这道题的时候觉得是这三道里面最简单的,结果果然不能轻敌,忘了队列长度会变,就全W了。正解:找规律,先从小到大排序,然后减去相同的一段数的值,直到k减不够。总之啊,遇到这类题,就是多画多手算,找规律,不要嫌麻烦而放弃。注意一些细节的问题。

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<cstring>
 4 #include<algorithm>
 5 #define ll long long
 6 using namespace std;
 7 const int maxn=100005;
 8 int n,same[maxn];
 9 ll k;
10 struct node{
11     int num;
12     ll ci;
13 };
14 node a[maxn];
15 const int comp1(const node &a,const node&b)
16 {
17     return a.ci<b.ci;
18 }
19 const int comp2(const node &a,const node&b)
20 {
21     return a.num<b.num;
22 }
23 int main()
24 {
25     freopen("B.input","r",stdin);
26     freopen("B.output","w",stdout);
27     cin>>n>>k;
28     for (int i=1;i<=n;i++)
29     {
30         scanf("%d",&a[i].ci);
31         a[i].num=i;
32     }
33     sort(a+1,a+1+n,comp1);
34     ll cnt=0,last=0,another=0;
35     for (int i=1;i<=n;i++)//预处理
36       if (a[i].ci!=a[i-1].ci)
37           same[cnt++]=i;
38     cnt=0;
39     while (k)
40     {
41         ll x=n-same[cnt]+1,y=a[same[cnt]].ci-last;
42         k-=(ll)(a[same[cnt]].ci-last)*(n-same[cnt]+1);
43         if (k>=0)
44         {
45             last=a[same[cnt]].ci;
46             cnt++;
47         }
48         else
49         {
50             k+=(ll)(a[same[cnt]].ci-last)*(n-same[cnt]+1);
51             last+=k/(n-same[cnt]+1);
52             k%=(n-same[cnt]+1);
53             break ;
54         }
55     }
56     sort(a+same[cnt],a+n+1,comp2);
57     for (int i=same[cnt];i<=n;i++)
58       a[i].ci-=last;
59     for (int i=same[cnt]+k;i<=n;i++)
60           if (a[i].ci) printf("%d ",a[i].num);
61     for (int i=same[cnt];i<same[cnt]+k;i++)
62      {
63          a[i].ci-=1;
64         if (a[i].ci) printf("%d ",a[i].num);
65      }
66     return 0;
67 }



  第三题:考试的时候想这个心情很浮躁,就不想深入思考。正解:拓扑排序,在学这个的时候就没有好好学,现在全忘了,还好有这道题,又复习了一遍:就是在队列中取出入度为0的点,并删除此点及以此点为起点的所有关联边,减入度,再把入度为0的push进队列。而这道题,虽然还有路径长度为2的边,但是可以发现,其实走长度为2的边与走长度为1的边到某个点的耗费是一样的,所以可以直接简化为只有长度为1的边来走。每个房间都有一个队列表示这个房间内入度为0即可以走的边,每走一次ans++,再走下一个房间,一直跑圈,直到所有任务都完成。

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<queue>
 4 using namespace std;
 5 const int maxn=205;
 6 int n;
 7 int ci[maxn],indgr[maxn],indgr2[maxn];//入度
 8 int tot,he[maxn],ne[maxn*maxn],to[maxn*maxn];//maxn*maxn
 9 queue<int> q[4];
10 void add(int a,int b)
11 {
12     tot ++;
13     ne[tot]=he[a];
14     to[tot]=b;
15     he[a]=tot;
16 }
17 int tuopu(int x)//每个房间一个队列,嵌套拓扑排序,选入度为0的开始
18 {
19     for (int i=1;i<=n;i++)
20     {
21         indgr2[i]=indgr[i];
22         if (indgr2[i]==0)
23           q[ci[i]].push(i);
24     }
25     int cnt=n,ans=0;
26     while (cnt){
27         while (!q[x].empty()){
28             int now=q[x].front();
29             q[x].pop();
30             cnt--;
31             for (int i=he[now];i;i=ne[i])
32             {
33                 indgr2[to[i]]--;
34                 if (indgr2[to[i]]==0) q[ci[to[i]]].push(to[i]);
35             }
36         }
37         if (cnt){
38             ans++;
39             x++;
40             if (x>3) x=1;
41         }
42     }
43     return ans+n;
44 }
45 int main()
46 {
47     freopen("C.input","r",stdin);
48     freopen("C.output","w",stdout);
49     cin>>n;
50     for (int i=1;i<=n;i++)
51       scanf("%d",&ci[i]);
52     for (int i=1;i<=n;i++)
53     {
54         scanf("%d",&indgr[i]);
55         for (int j=1;j<=indgr[i];j++)
56         {
57             int x;
58             scanf("%d",&x);
59             add(x,i);
60         }
61     }
62     printf("%d",min(tuopu(1),min(tuopu(2),tuopu(3)) ) );
63     return 0;
64 } 



  总的来说,需要注意的是,在考试的时候,千万不要出神,静下心来慢慢想,不要自我放弃,相信自己,就一定可以。每次把自己的问题弄懂,把每一道题弄懂再做,自己编。想题的时候,从最简单的开始分析,逐步深入,确保每一步分析都没有错。

时间: 2024-12-28 01:35:11

【模拟题(63550802...)】解题报告【贪心】【拓扑排序】【找规律】【树相关】的相关文章

2016 第七届蓝桥杯 c/c++ B组省赛真题及解题报告

2016 第七届蓝桥杯 c/c++ B组省赛真题及解题报告 勘误1:第6题第4个 if最后一个条件粗心写错了,答案应为1580. 条件应为abs(a[3]-a[7])!=1,宝宝心理苦啊.!感谢zzh童鞋的提醒. 勘误2:第7题在推断连通的时候条件写错了,后两个if条件中是应该是<=12 落了一个等于号.正确答案应为116. 1.煤球数目 有一堆煤球.堆成三角棱锥形.详细: 第一层放1个, 第二层3个(排列成三角形), 第三层6个(排列成三角形), 第四层10个(排列成三角形). -. 假设一共

【CodeForces】915 D. Almost Acyclic Graph 拓扑排序找环

[题目]D. Almost Acyclic Graph [题意]给定n个点的有向图(无重边),问能否删除一条边使得全图无环.n<=500,m<=10^5. [算法]拓扑排序 [题解]找到一个简单环,则欲删除的边一定经过该环.尝试环上的每一条边(至多n条边)后再次拓扑排序判断全图是否有环. 拓扑排序后定位到简单环:剩余图是环+环内DAG,DFS过程中将走入死路的点标-1,访问过标1,找到访问过的点就是简单环.换起始点直到找到环为止. 复杂度O(nm). #include<cstdio>

暑假第二次考试 冲刺Noip2017模拟赛2 解题报告——五十岚芒果酱

题1 牛跑步(running) [题目描述] 新牛到部队,CG 要求它们每天早上搞晨跑,从 A 农场跑到 B 农场.从 A 农场到 B 农场中有 n-2 个路口,分别标上号,A 农场为 1 号,B 农场为 n 号,路口分别为 2...n-1 号,从 A 农场到 B 农场有很多条路径可以到达,而 CG 发现有的路口是必须经过的,即每条路径都经过的路口,CG 要把它们记录下来,这样 CG 就可以先到那个路口,观察新牛们有没有偷懒,而你的任务就是找出所有必经路口. [输入格式] 第一行两个用空格隔开的

Moscow Pre-Finals Workshop 2016. Japanese School OI Team Selection. 套题详细解题报告

写在前面 谨以此篇题解致敬出题人! 真的期盼国内也能多出现一些这样质量的比赛啊.9道题中,没有一道凑数的题目,更没有码农题,任何一题拿出来都是为数不多的好题.可以说是这一年打过的题目质量最棒的五场比赛之一了!(其中G.I和D题简直是好题中的好题!) 由于网上没有任何这套题的题解,我每道题都绞尽脑汁想了好久(尤其是D题.I题和H题证明),在此认认真真的写一篇博客,也真心希望好题能被更多的人发现和赞美. 题目概述 题目 思维难度  推荐指数 考点 A 3  ☆☆☆☆ 最长上升子序列 B 暂留坑,>7

hdu-5695 Gym Class(贪心+拓扑排序)

题目链接: Gym Class Time Limit: 6000/1000 MS (Java/Others)     Memory Limit: 65536/65536 K (Java/Others) Problem Description 众所周知,度度熊喜欢各类体育活动. 今天,它终于当上了梦寐以求的体育课老师.第一次课上,它发现一个有趣的事情.在上课之前,所有同学要排成一列, 假设最开始每个人有一个唯一的ID,从1到N,在排好队之后,每个同学会找出包括自己在内的前方所有同学的最小ID,作为

2016&quot;百度之星&quot; - 初赛(Astar Round2A)1006 Gym Class(HDU5695)——贪心+拓扑排序

分析:首先,利用贪心可知,如果要所有人的分数和最高,需要把序号大的优先放在前面.其次,对于a的前面不能为b,那么只能a在b前面了,那么就建立一条从a到b的边,并且b的入度加1.然后就是拓扑排序了.要分数最高,则把哪些入度为0的点(他们不需要有哪些人一定要在他们前面,最自由)丢进优先队列,然后就可以实现把序号大的尽量放在前面而且满足题意了. 具体见代码: 1 #include <stdio.h> 2 #include <algorithm> 3 #include <string

贪心+拓扑排序 AOJ 2456 Usoperanto

题目传送门 题意:给出一条链,比如x连到y,x一定要在y的左边,且代价是这条链经过的点的权值和,问如何排序使得代价最小 分析:类似拓扑排序,先把入度为0的点入队,把指向该点的所有点按照权值排序,保证这样是代价是最小的,然后把这一块看成一个点继续入队.看图更简单: /************************************************ * Author :Running_Time * Created Time :2015/10/3 星期六 13:02:41 * File

hdu 5195 DZY Loves Topological Sorting BestCoder Round #35 1002 [ 拓扑排序 + 优先队列 || 线段树 ]

传送门 DZY Loves Topological Sorting Time Limit: 4000/2000 MS (Java/Others)    Memory Limit: 131072/131072 K (Java/Others)Total Submission(s): 221    Accepted Submission(s): 52 Problem Description A topological sort or topological ordering of a directed

【日常学习】【拓扑排序】家谱树&amp;FZU1483 Sicily1424 奖金 题解

拓扑排序的定义 简单来说就是给你一个图写出一个序列 图中如果a通向b 那么序列中A必须排在B前面 拓扑排序可能有很多结果 必须是有向无环图 可以利用拓扑排序来判定环的存在 当然也可以用神奇的SPFA 但是拓扑排序时间复杂度很低 只有O(V+E) 基本实现思路是 每次取出入度为0的点 然后删除与它相连的边 直到没有边  如果还有边但是找不到入度为0的点 说明有环 学习这个算法联系了两道题目 很经典很单纯 但是一般没有OJ有评测 奖金这道题目在福州大学OJ和中山大学萌萌哒Sicily上找到了评测(为