此处有目录↑
3h内只AC了L1-1 ~ L1-8、L2-1 ~ L2-3、L3-2
L3-1就快写完了,还是手速太慢 【已补完】
L2-4(小根堆忘了如何写了...)【已补完】和L3-3没时间看了
比赛网址:https://www.patest.cn/contests/2016gplt-1
交题网址: https://www.patest.cn/contests/gplt
一个整数“犯二的程度”定义为该数字中包含2的个数与其位数的比值。如果这个数是负数,则程度增加0.5倍;如果还是个偶数,则再增加1倍。例如数字“-13142223336”是个11位数,其中有3个2,并且是负数,也是偶数,则它的犯二程度计算为:3/11*1.5*2*100%,约为81.82%。本题就请你计算一个给定整数到底有多二。
输入格式:
输入第一行给出一个不超过50位的整数N。
输出格式:
在一行中输出N犯二的程度,保留小数点后两位。
输入样例:-13142223336输出样例:
81.82%
#include
#include
#include
using namespace std;
int len;
char s[55];
double ans,num1,num2;
int main() {
while(1==scanf("%s",s)) {
num1=num2=1;
len=strlen(s);
ans=0;
for(int i=0;i
微博上有个自称“大笨钟V”的家伙,每天敲钟催促码农们爱惜身体早点睡觉。不过由于笨钟自己作息也不是很规律,所以敲钟并不定时。一般敲钟的点数是根据敲钟时间而定的,如果正好在某个整点敲,那么“当”数就等于那个整点数;如果过了整点,就敲下一个整点数。另外,虽然一天有24小时,钟却是只在后半天敲1~12下。例如在23:00敲钟,就是“当当当当当当当当当当当”,而到了23:01就会是“当当当当当当当当当当当当”。在午夜00:00到中午12:00期间(端点时间包括在内),笨钟是不敲的。
下面就请你写个程序,根据当前时间替大笨钟敲钟。
输入格式:
输入第一行按照“hh:mm”的格式给出当前时间。其中hh是小时,在00到23之间;mm是分钟,在00到59之间。
输出格式:
根据当前时间替大笨钟敲钟,即在一行中输出相应数量个“Dang”。如果不是敲钟期,则输出:
Only hh:mm. Too early to Dang.
其中“hh:mm”是输入的时间。
输入样例1:19:05输出样例1:
DangDangDangDangDangDangDangDang输入样例2:
07:05输出样例2:
Only 07:05. Too early to Dang.
按照题目要求判断即可
若hh<12||(hh==12&&mm==0),则不敲钟,注意需要格式输出
否则,若mm==0,输出hh-12次Dang;若mm!=0,输出hh-11次Dang
#include
#include
#include
using namespace std;
int h,m;
int main() {
while(2==scanf("%d:%d",&h,&m)) {
if(h<12||(h==12&&m==0)) {
printf("Only %02d:%02d. Too early to Dang.\n",h,m);
}
else {
h-=12;
if(m!=0) {
++h;
}
while(h-->0) {
printf("Dang");
}
printf("\n");
}
}
return 0;
}
划拳是古老中国酒文化的一个有趣的组成部分。酒桌上两人划拳的方法为:每人口中喊出一个数字,同时用手比划出一个数字。如果谁比划出的数字正好等于两人喊出的数字之和,谁就输了,输家罚一杯酒。两人同赢或两人同输则继续下一轮,直到唯一的赢家出现。
下面给出甲、乙两人的酒量(最多能喝多少杯不倒)和划拳记录,请你判断两个人谁先倒。
输入格式:
输入第一行先后给出甲、乙两人的酒量(不超过100的非负整数),以空格分隔。下一行给出一个正整数N(<=100),随后N行,每行给出一轮划拳的记录,格式为:
甲喊 甲划 乙喊 乙划
其中“喊”是喊出的数字,“划”是划出的数字,均为不超过100的正整数(两只手一起划)。
输出格式:
在第一行中输出先倒下的那个人:A代表甲,B代表乙。第二行中输出没倒的那个人喝了多少杯。题目保证有一个人倒下。注意程序处理到有人倒下就终止,后面的数据不必处理。
输入样例:1 1 6 8 10 9 12 5 10 5 10 3 8 5 12 12 18 1 13 4 16 12 15 15 1 1 16输出样例:
A 1
直接判断每次输赢即可,若有人倒下,则读入的数据不再判断输赢,需要注意必须是一人赢,另一人输,才会有人喝酒
#include
#include
#include
using namespace std;
int loseeA,loseeB,n;
int pA,sA,pB,sB,cntA,cntB,cups;
char lose;
int main() {
while(2==scanf("%d%d",&loseeA,&loseeB)) {
lose='\0';
cntA=cntB=0;
scanf("%d",&n);
while(n-->0) {
scanf("%d%d%d%d",&pA,&sA,&pB,&sB);
if(lose=='\0') {
if(sA==pA+pB&&sB!=pA+pB) {
++cntA;
if(cntA>loseeA) {
lose='A';
cups=cntB;
}
}
else if(sA!=pA+pB&&sB==pA+pB) {
++cntB;
if(cntB>loseeB) {
lose='B';
cups=cntA;
}
}
}
}
printf("%c\n%d\n",lose,cups);
}
return 0;
}
当芸芸众生忙着在朋友圈中发照片的时候,总有一些人因为太帅而没有朋友。本题就要求你找出那些帅到没有朋友的人。
输入格式:
输入第一行给出一个正整数N(<=100),是已知朋友圈的个数;随后N行,每行首先给出一个正整数K(<=1000),为朋友圈中的人数,然后列出一个朋友圈内的所有人——为方便起见,每人对应一个ID号,为5位数字(从00000到99999),ID间以空格分隔;之后给出一个正整数M(<=10000),为待查询的人数;随后一行中列出M个待查询的ID,以空格分隔。
注意:没有朋友的人可以是根本没安装“朋友圈”,也可以是只有自己一个人在朋友圈的人。虽然有个别自恋狂会自己把自己反复加进朋友圈,但题目保证所有K超过1的朋友圈里都至少有2个不同的人。
输出格式:
按输入的顺序输出那些帅到没朋友的人。ID间用1个空格分隔,行的首尾不得有多余空格。如果没有人太帅,则输出“No one is handsome”。
注意:同一个人可以被查询多次,但只输出一次。
输入样例1:3 3 11111 22222 55555 2 33333 44444 4 55555 66666 99999 77777 8 55555 44444 10000 88888 22222 11111 23333 88888输出样例1:
10000 88888 23333输入样例2:
3 3 11111 22222 55555 2 33333 44444 4 55555 66666 99999 77777 4 55555 44444 22222 11111输出样例2:
No one is handsome
直接用bool数组标记某个人是否处于一个朋友圈中即可,只需要注意朋友圈只有一人时不标记
查询时,再用bool数组标记该人是否被查询过,没有查询过就存入数组,最后按照总人数格式化输出即可
注意:输出人时需要输出5位数字,即包含前导0,查了好久才发现,要不然就有时间了
#include
#include
#include
using namespace std;
int n,num,people;
int ans[10005],tot;
bool notHandsome[100005];
bool vis[100005];
int main() {
while(1==scanf("%d",&n)) {
memset(notHandsome,false,sizeof(notHandsome));
memset(vis,false,sizeof(vis));
while(n-->0) {
scanf("%d",&num);
for(int i=0;i0) {
scanf("%d",&people);
if(!vis[people]) {
vis[people]=true;
if(!notHandsome[people]) {
ans[tot++]=people;
}
}
}
if(tot==0) {
printf("No one is handsome\n");
}
else {
printf("%05d",ans[0]);
for(int i=1;i
这道超级简单的题目没有任何输入。
你只需要把这句很重要的话 —— “I'm gonna WIN!”——连续输出三遍就可以了。
注意每遍占一行,除了每行的回车不能有任何多余字符。
按照题目要求输出即可
#include
#include
#include
using namespace std;
int main() {
printf("I'm gonna WIN!\n");
printf("I'm gonna WIN!\n");
printf("I'm gonna WIN!\n");
return 0;
}
给定N个正整数,请统计奇数和偶数各有多少个?
输入格式:
输入第一行给出一个正整N(<= 1000);第2行给出N个正整数,以空格分隔。
输出格式:
在一行中先后输出奇数的个数、偶数的个数。中间以1个空格分隔。
输入样例:9 88 74 101 26 15 0 34 22 77输出样例:
3 6
#include
#include
#include
using namespace std;
int n,a,no,ne;
int main() {
while(1==scanf("%d",&n)) {
no=ne=0;
while(n-->0) {
scanf("%d",&a);
if((a&1)==1) {
++no;
}
else {
++ne;
}
}
printf("%d %d\n",no,ne);
}
return 0;
}
给定一个长度不超过10000的、仅由英文字母构成的字符串。请将字符重新调整顺序,按“GPLTGPLT....”这样的顺序输出,并忽略其它字符。当然,四种字符(不区分大小写)的个数不一定是一样多的,若某种字符已经输出完,则余下的字符仍按GPLT的顺序打印,直到所有字符都被输出。
输入格式:
输入在一行中给出一个长度不超过10000的、仅由英文字母构成的非空字符串。
输出格式:
在一行中按题目要求输出排序后的字符串。题目保证输出非空。
输入样例:pcTclnGloRgLrtLhgljkLhGFauPewSKgt输出样例:
GPLTGPLTGLTGLGLL
统计字符串中各所需字符的出现次数,以及所有所需字符出现的总次数
输出时,若还有能输出的所需字符,则进入循环,按照顺序输出还能输出的所需字符
#include
#include
#include
using namespace std;
char s[10005];
int num[5];
const char ch[5]={"GPLT"};
int main() {
while(1==scanf("%s",s)) {
num[0]=num[1]=num[2]=num[3]=0;
for(int i=0;s[i]!='\0';++i) {
if(s[i]=='G'||s[i]=='g') {
++num[0];
++num[4];
}
if(s[i]=='P'||s[i]=='p') {
++num[1];
++num[4];
}
if(s[i]=='L'||s[i]=='l') {
++num[2];
++num[4];
}
if(s[i]=='T'||s[i]=='t') {
++num[3];
++num[4];
}
}
while(num[4]>0) {
for(int i=0;i<4;++i) {
if(num[i]>0) {
--num[i];
--num[4];
printf("%c",ch[i]);
}
}
}
printf("\n");
}
return 0;
}
如果今天是星期三,后天就是星期五;如果今天是星期六,后天就是星期一。我们用数字1到7对应星期一到星期日。给定某一天,请你输出那天的“后天”是星期几。
输入格式:
输入第一行给出一个正整数D(1 <= D <=7),代表星期里的某一天。
输出格式:
在一行中输出D天的后天是星期几。
输入样例:3输出样例:
5
#include
#include
#include
using namespace std;
int n;
int main() {
while(1==scanf("%d",&n)) {
n=(n+2)%7;
if(n==0) {
n=7;
}
printf("%d\n",n);
}
return 0;
}
没有人没抢过红包吧…… 这里给出N个人之间互相发红包、抢红包的记录,请你统计一下他们抢红包的收获。
输入格式:
输入第一行给出一个正整数N(<= 104),即参与发红包和抢红包的总人数,则这些人从1到N编号。随后N行,第i行给出编号为i的人发红包的记录,格式如下:
K N1 P1 ... NK PK
其中K(0 <= K <= 20)是发出去的红包个数,Ni是抢到红包的人的编号,Pi(> 0)是其抢到的红包金额(以分为单位)。注意:对于同一个人发出的红包,每人最多只能抢1次,不能重复抢。
输出格式:
按照收入金额从高到低的递减顺序输出每个人的编号和收入金额(以元为单位,输出小数点后2位)。每个人的信息占一行,两数字间有1个空格。如果收入金额有并列,则按抢到红包的个数递减输出;如果还有并列,则按个人编号递增输出。
输入样例:10 3 2 22 10 58 8 125 5 1 345 3 211 5 233 7 13 8 101 1 7 8800 2 1 1000 2 1000 2 4 250 10 320 6 5 11 9 22 8 33 7 44 10 55 4 2 1 3 8800 2 1 23 2 123 1 8 250 4 2 121 4 516 7 112 9 10输出样例:
1 11.63 2 3.63 8 3.63 3 2.11 7 1.69 6 -1.67 9 -2.18 10 -3.26 5 -3.26 4 -12.32
按照题意模拟资金的流入与流出即可,注意发红包的人需要减去其发红包的金额总和
然后按照题目要求排序即可
#include
#include
#include
using namespace std;
struct Node {
int index,num,money;
bool operator < (const Node& a) const {
if(money!=a.money) {
return money>a.money;
}
return num>a.num||(index0) {
scanf("%d%d",&nn,&pp);
people[i].money-=pp;
people[nn].money+=pp;
++people[nn].num;
}
}
sort(people+1,people+1+n);
for(int i=1;i<=n;++i) {
printf("%d %.2lf\n",people[i].index,0.01*people[i].money);
}
}
return 0;
}
布置宴席最微妙的事情,就是给前来参宴的各位宾客安排座位。无论如何,总不能把两个死对头排到同一张宴会桌旁!这个艰巨任务现在就交给你,对任何一对客人,请编写程序告诉主人他们是否能被安排同席。
输入格式:
输入第一行给出3个正整数:N(<= 100),即前来参宴的宾客总人数,则这些人从1到N编号;M为已知两两宾客之间的关系数;K为查询的条数。随后M行,每行给出一对宾客之间的关系,格式为:“宾客1 宾客2 关系”,其中“关系”为1表示是朋友,-1表示是死对头。注意两个人不可能既是朋友又是敌人。最后K行,每行给出一对需要查询的宾客编号。
这里假设朋友的朋友也是朋友。但敌人的敌人并不一定就是朋友,朋友的敌人也不一定是敌人。只有单纯直接的敌对关系才是绝对不能同席的。
输出格式:
对每个查询输出一行结果:如果两位宾客之间是朋友,且没有敌对关系,则输出“No problem”;如果他们之间并不是朋友,但也不敌对,则输出“OK”;如果他们之间有敌对,然而也有共同的朋友,则输出“OK but...”;如果他们之间只有敌对关系,则输出“No way”。
输入样例:7 8 4 5 6 1 2 7 -1 1 3 1 3 4 1 6 7 -1 1 2 1 1 4 1 2 3 -1 3 4 5 7 2 3 7 2输出样例:
No problem OK OK but... No way
用并查集维护朋友关系
用enemy[i][j]表示i和j有没有直接的敌对关系
然后根据查询结果按照题目要求输出不同的信息
#include
#include
#include
using namespace std;
int n,m,k,g1,g2,r,p1,p2;
int par[105];
bool enemy[105][105];
int getPar(int a) {
if(par[a]!=a) {
par[a]=getPar(par[a]);
}
return par[a];
}
int main() {
while(3==scanf("%d%d%d",&n,&m,&k)) {
for(int i=1;i<=n;++i) {
par[i]=i;
for(int j=i;j<=n;++j) {
enemy[i][j]=enemy[j][i]=false;
}
}
while(m-->0) {
scanf("%d%d%d",&g1,&g2,&r);
if(r==1) {
p1=getPar(g1);
p2=getPar(g2);
if(p1!=p2) {
par[p1]=p2;
}
}
else {
enemy[g1][g2]=enemy[g2][g1]=true;
}
}
while(k-->0) {
scanf("%d%d",&g1,&g2);
if(getPar(g1)==getPar(g2)) {
printf("%s\n",enemy[g1][g2]?"OK but...":"No problem");
}
else {
printf("%s\n",enemy[g1][g2]?"No way":"OK");
}
}
}
return 0;
}
给定一棵二叉树的中序遍历和前序遍历,请你先将树做个镜面反转,再输出反转后的层序遍历的序列。所谓镜面反转,是指将所有非叶结点的左右孩子对换。这里假设键值都是互不相等的正整数。
输入格式:
输入第一行给出一个正整数N(<=30),是二叉树中结点的个数。第二行给出其中序遍历序列。第三行给出其前序遍历序列。数字间以空格分隔。
输出格式:
在一行中输出该树反转后的层序遍历的序列。数字间以1个空格分隔,行首尾不得有多余空格。
输入样例:7 1 2 3 4 5 6 7 4 1 3 2 6 5 7输出样例:
4 6 1 7 5 3 2
和模拟赛的一样类型的题,代码改一下就能重新建立二叉树
不必做镜像反转,只用在层次遍历的时候,先加入右儿子结点,再加入左儿子结点即可
#include
#include
#include
using namespace std;
const int MAXN=35;
int n,cnt,root;
int inod[MAXN],preod[MAXN];
int q[35],head,tail;
struct Node {
int lson,rson,num;
}tr[MAXN];
int dfs(int pl,int pr,int il,int ir) {
if(pl==pr) {
tr[cnt].lson=tr[cnt].rson=-1;
tr[cnt].num=preod[pl];
return cnt++;
}
for(int i=il;i<=ir;++i) {
if(preod[pl]==inod[i]) {
int cur=cnt++;
tr[cur].lson=tr[cur].rson=-1;
tr[cur].num=preod[pl];
if(il
将一系列给定数字顺序插入一个初始为空的小顶堆H[]。随后判断一系列相关命题是否为真。命题分下列几种:
输入格式:
每组测试第1行包含2个正整数N(<= 1000)和M(<= 20),分别是插入元素的个数、以及需要判断的命题数。下一行给出区间[-10000, 10000]内的N个要被插入一个初始为空的小顶堆的整数。之后M行,每行给出一个命题。题目保证命题中的结点键值都是存在的。
输出格式:
对输入的每个命题,如果其为真,则在一行中输出“T”,否则输出“F”。
输入样例:5 4 46 23 26 24 10 24 is the root 26 and 23 are siblings 46 is the parent of 23 23 is a child of 10输出样例:
F T F T
本来还怕存在重复的键值,但是这样就无法进行查询,就推测出应该键值唯一,然后用数组标记即可
#include
#include
#include
using namespace std;
const int ORD=10002;
int n,m,a[1005],indx[20005],x,y;
char cmd[25],tmp[25];
void minHeapUp(int i) {
if(i==1) {
return ;
}
int p=i>>1;
if(a[i]0) {
scanf("%d%s",&x,cmd);
if(cmd[0]=='a') {
scanf("%d%s%s",&y,cmd,tmp);
printf("%c\n",(indx[x+ORD]>>1)==(indx[y+ORD]>>1)?'T':'F');
}
else {
scanf("%s%s",tmp,cmd);
if(cmd[0]=='r') {
printf("%c\n",indx[x+ORD]==1?'T':'F');
}
else if(cmd[0]=='p') {
scanf("%s%d",tmp,&y);
printf("%c\n",indx[x+ORD]==(indx[y+ORD]>>1)?'T':'F');
}
else {
scanf("%s%d",tmp,&y);
printf("%c\n",(indx[x+ORD]>>1)==indx[y+ORD]?'T':'F');
}
}
}
}
return 0;
}
本题要求你实现一个天梯赛专属在线地图,队员输入自己学校所在地和赛场地点后,该地图应该推荐两条路线:一条是最快到达路线;一条是最短距离的路线。题目保证对任意的查询请求,地图上都至少存在一条可达路线。
输入格式:
输入在第一行给出两个正整数N(2 <= N <=500)和M,分别为地图中所有标记地点的个数和连接地点的道路条数。随后M行,每行按如下格式给出一条道路的信息:
V1 V2 one-way length time
其中V1和V2是道路的两个端点的编号(从0到N-1);如果该道路是从V1到V2的单行线,则one-way为1,否则为0;length是道路的长度;time是通过该路所需要的时间。最后给出一对起点和终点的编号。
输出格式:
首先按下列格式输出最快到达的时间T和用节点编号表示的路线:
Time = T: 起点 => 节点1 => ... => 终点
然后在下一行按下列格式输出最短距离D和用节点编号表示的路线:
Distance = D: 起点 => 节点1 => ... => 终点
如果最快到达路线不唯一,则输出几条最快路线中最短的那条,题目保证这条路线是唯一的。而如果最短距离的路线不唯一,则输出途径节点数最少的那条,题目保证这条路线是唯一的。
如果这两条路线是完全一样的,则按下列格式输出:
Time = T; Distance = D: 起点 => 节点1 => ... => 终点
输入样例1:10 15 0 1 0 1 1 8 0 0 1 1 4 8 1 1 1 5 4 0 2 3 5 9 1 1 4 0 6 0 1 1 7 3 1 1 2 8 3 1 1 2 2 5 0 2 2 2 1 1 1 1 1 5 0 1 3 1 4 0 1 1 9 7 1 1 3 3 1 0 2 5 6 3 1 2 1 5 3输出样例1:
Time = 6: 5 => 4 => 8 => 3 Distance = 3: 5 => 1 => 3输入样例2:
7 9 0 4 1 1 1 1 6 1 3 1 2 6 1 1 1 2 5 1 2 2 3 0 0 1 1 3 1 1 3 1 3 2 1 2 1 4 5 0 2 2 6 5 1 2 1 3 5输出样例2:
Time = 3; Distance = 4: 3 => 2 => 5
然后两个最短路唯一的不同就是:第一关键字和第二关键字不同
处理完最短路后比较路径,按照题目要求输出即可
发现貌似距离最短路更新时,第二关键字(所经点的个数)并不影响,刚开始没有给cnt[e]赋值也AC了,看来还是数据比较水
#include
#include
#include
#include
#include
using namespace std;
const int MAXN=505;
struct Node {
int e,d,t;
Node(int ee,int dd,int tt):e(ee),d(dd),t(tt) {}
bool operator < (const Node& a) const {
if(t!=a.t) {
return t>a.t;
}
return d>a.d;
}
}cur(0,0,0);
int n,m,s,e,type,t,d,sta,des,tmp;
vector g[MAXN];
priority_queue q;
int tim[MAXN],dis[MAXN],pre[MAXN],cnt[MAXN];
int ans_t[MAXN],num_t,ans_d[MAXN],num_d,Time,Distance;
void Dijkstra_t() {//时间最短的最短路;e代表点,d代表距离,t代表时间
memset(tim,0x3f,sizeof(tim));
memset(dis,0x3f,sizeof(dis));
priority_queue q;
q.push(Node(sta,0,0));
tim[sta]=dis[sta]=0;
while(!q.empty()) {
cur=q.top();
q.pop();
for(int i=g[cur.e].size()-1;i>=0;--i) {
e=g[cur.e][i].e;
d=cur.d+g[cur.e][i].d;
t=cur.t+g[cur.e][i].t;
if(t q;
q.push(Node(sta,0,0));
tim[sta]=dis[sta]=0;
while(!q.empty()) {
cur=q.top();
q.pop();
for(int i=g[cur.e].size()-1;i>=0;--i) {
e=g[cur.e][i].e;
d=cur.d+g[cur.e][i].d;
t=cur.t+1;
if(d=0;--i) {
if(ans_t[i]!=ans_d[i]) {
return false;
}
}
return true;
}
int main() {
while(2==scanf("%d%d",&n,&m)) {
for(int i=0;i0) {
scanf("%d%d%d%d%d",&s,&e,&type,&d,&t);
g[s].push_back(Node(e,d,t));
if(type==0) {
g[e].push_back(Node(s,d,t));
}
}
scanf("%d%d",&sta,&des);
Dijkstra_t();
tmp=des;
num_t=0;
while(tmp!=sta) {
ans_t[num_t++]=tmp;
tmp=pre[tmp];
}
Time=tim[des];
Dijkstra_d();
tmp=des;
num_d=0;
while(tmp!=sta) {
ans_d[num_d++]=tmp;
tmp=pre[tmp];
}
Distance=dis[des];
if(isEqual()) {
printf("Time = %d; Distance = %d: %d",Time,Distance,sta);
while(--num_t>=0) {
printf(" => %d",ans_t[num_t]);
}
}
else {
printf("Time = %d: %d",Time,sta);
while(--num_t>=0) {
printf(" => %d",ans_t[num_t]);
}
printf("\nDistance = %d: %d",Distance,sta);
while(--num_d>=0) {
printf(" => %d",ans_d[num_d]);
}
}
printf("\n");
}
return 0;
}
喊山,是人双手围在嘴边成喇叭状,对着远方高山发出“喂—喂喂—喂喂喂……”的呼唤。呼唤声通过空气的传递,回荡于深谷之间,传送到人们耳中,发出约定俗成的“讯号”,达到声讯传递交流的目的。原来它是彝族先民用来求援呼救的“讯号”,慢慢地人们在生活实践中发现了它的实用价值,便把它作为一种交流工具世代传袭使用。(图文摘自:http://news.xrxxw.com/newsshow-8018.html)
一个山头呼喊的声音可以被临近的山头同时听到。题目假设每个山头最多有两个能听到它的临近山头。给定任意一个发出原始信号的山头,本题请你找出这个信号最远能传达到的地方。
输入格式:
输入第一行给出3个正整数n、m和k,其中n(<=10000)是总的山头数(于是假设每个山头从1到n编号)。接下来的m行,每行给出2个不超过n的正整数,数字间用空格分开,分别代表可以听到彼此的两个山头的编号。这里保证每一对山头只被输入一次,不会有重复的关系输入。最后一行给出k(<=10)个不超过n的正整数,数字间用空格分开,代表需要查询的山头的编号。
输出格式:
依次对于输入中的每个被查询的山头,在一行中输出其发出的呼喊能够连锁传达到的最远的那个山头。注意:被输出的首先必须是被查询的个山头能连锁传到的。若这样的山头不只一个,则输出编号最小的那个。若此山头的呼喊无法传到任何其他山头,则输出0。
输入样例:7 5 4 1 2 2 3 3 1 4 5 5 6 1 4 5 7输出样例:
2 6 4 0
可以抽象为题目给了一个边权值为1的无向稀疏图(现在再仔细读题,就是一些链(或者环)么),然后可以直接bfs,找到路最长的点即可
因为本题可能存在一个环,所以不能直接dfs或者用链表模拟,否则可能会误判起始点的相邻点为最远点
例如:
2—4
| |
1—3
用dfs或者链表模拟,就会误判以1为起点的最远点为2,而正确答案为4
#include
#include
#include
#include
using namespace std;
const int MAXN=10005;
int n,m,k,s,e,mxdis;
vector g[MAXN];
int q[MAXN],head,tail;
int dis[MAXN];
int main() {
while(3==scanf("%d%d%d",&n,&m,&k)) {
for(int i=1;i<=n;++i) {
g[i].clear();
}
while(m-->0) {
scanf("%d%d",&s,&e);
g[s].push_back(e);
g[e].push_back(s);
}
while(k-->0) {
scanf("%d",&s);
if(g[s].size()==0) {
printf("0\n");
}
else {
memset(dis,-1,sizeof(dis));
mxdis=head=tail=0;
dis[s]=0;
q[tail++]=s;
while(head!=tail) {
s=q[head++];
for(int i=g[s].size()-1;i>=0;--i) {
e=g[s][i];
if(dis[e]==-1) {
dis[e]=dis[s]+1;
mxdis=max(mxdis,dis[e]);
q[tail++]=e;
}
}
}
for(int i=1;i<=n;++i) {
if(dis[i]==mxdis) {
printf("%d\n",i);
break;
}
}
}
}
}
return 0;
}