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

【模拟题(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 road29 {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         else49         {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

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

 

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