• 【模拟题(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 }
    View Code

      第二题:先开始看这道题的时候觉得是这三道里面最简单的,结果果然不能轻敌,忘了队列长度会变,就全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 }
    View Code

      第三题:考试的时候想这个心情很浮躁,就不想深入思考。正解:拓扑排序,在学这个的时候就没有好好学,现在全忘了,还好有这道题,又复习了一遍:就是在队列中取出入度为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 } 
    View Code

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

  • 相关阅读:
    BeanFactory not initialized or already closed
    点击程序不弹出界面,但有后台服务
    python获取一年所有的日期
    keepalived实现高可用
    解决docker镜像pull超时问题
    docker容器的操作
    docker小结
    docker概述
    docker镜像操作
    python批量下载
  • 原文地址:https://www.cnblogs.com/lx0319/p/5819826.html
Copyright © 2020-2023  润新知