HNUCM2020年春季ACM集训队热身赛-第2场题解

问题 A: 河畔军训
题目描述

河畔镇是一个景色秀丽,气候宜人的度假胜地,每天都会有很多的游客来这里游玩。但奇怪的是这里总会出现一些潜伏者。果不其然,通过保卫者的跟踪,发现在河畔镇的地下隐藏着Blitz的秘密武器实验室。最危险的地方也是最安全的地方,这里人多,所以只能采用狙击作战,一场“无声无息“的战斗即刻打响。
每到周末小z,小y便开始在河畔军训小h(当然有时也会被反军训)。
不过他们军训采用刀战(即相遇时才可军训)
每当小z,小y,小h三人在河畔整相遇时,小z和小y便可军训小h
由于小h有兔耳朵buff加成,小h每秒最多可以移动3步,且可以选择上/下/左/右/左上/左下/右上/右下8个方向移动
小z,小y每秒均只能移动1步,只能上/下/左/右4个方向移动。
当然,三人均可选择保持原地不动。
三人移动始终在地图范围内。
下面,给你河畔的地图以及小z,小y,小h的初始坐标。
请你求出最快军训小h的时间(即3人相遇的最短时间),如果无法军训小h则输出“lack of junxun”

输入

多组数据
每组数据第一行两个整数N,M(1<=N,M<=1000)代表河畔地图的行和列
接下来是N*M大小的地图
其中“z”,“y”,“h”分别代表小z,小y,小h的初始坐标
“#”代表障碍物,“.”表示可以正常通过的位置

输出

对于每组数据
如果能军训小h,则输出最快军训小h所需的时间
否则,输出“lack of junxun”

样例输入

2 4
z…h
#y#.
2 3
z#y
#h.

样例输出

1
lack of junxun

思路

分别从三个起点开始用bfs进行模拟…看一下代码就懂了

#include <bits/stdc++.h>
using namespace std;
const int maxn=1e5+5;
int n,m;
char w[1005][1005];
int vis[3][1005][1005];
int dir[8][2]={0,1,0,-1,1,0,-1,0,1,1,-1,-1,1,-1,-1,1};
struct node{
    int x,y;
};
bool ju(int x,int y,int id){//判断是否可走
    if(x>=1&&x<=n&&y>=1&&y<=m&&w[x][y]!='#'&&vis[id][x][y]==0)
        return true;
    return false;
}
queue<node> pq[3];
bool bfs(int x){
    int num=pq[x].size();
    node now,ne;
    while(num--){
        now=pq[x].front(),pq[x].pop();
        for(int i=0;i<8;++i){
            if(i>=4&&(x==0||x==1))//z和y不能走斜线,break出去
                break;
            ne.x=now.x+dir[i][0];
            ne.y=now.y+dir[i][1];
            if(ju(ne.x,ne.y,x)){
                vis[x][ne.x][ne.y]=1;
                pq[x].push(ne);
                if(vis[0][ne.x][ne.y]&&vis[1][ne.x][ne.y]&&vis[2][ne.x][ne.y]){//如果某一个点3个人都走过,说明可以会合
                    return true;
                }
            }
        }
    }
    return false;
}
int solve(){
    int step=0;//步数
    while(!pq[0].empty()||!pq[1].empty()||!pq[2].empty()){
        ++step;
        if(bfs(0))return step;
        if(bfs(1))return step;
        for(int i=1;i<=3;++i)
            if(bfs(2))return step;
    }
    return -1;
}
int main()
{
    while(~scanf("%d %d",&n,&m)){
        memset(vis,0,sizeof(vis));
        while(!pq[0].empty())pq[0].pop();
        while(!pq[1].empty())pq[1].pop();
        while(!pq[2].empty())pq[2].pop();
        node now;
        for(int i=1;i<=n;++i)
            scanf("%s",w[i]+1);
        for(int i=1;i<=n;++i){
            for(int j=1;j<=m;++j){
                if(w[i][j]=='z'){
                    now.x=i,now.y=j;
                    vis[0][now.x][now.y]=1;
                    pq[0].push(now);
                }else if(w[i][j]=='y'){
                    now.x=i,now.y=j;
                    vis[1][now.x][now.y]=1;
                    pq[1].push(now);
                }else if(w[i][j]=='h'){
                    now.x=i,now.y=j;
                    vis[2][now.x][now.y]=1;
                    pq[2].push(now);
                }
            }
        }
        int ans=solve();
        if(ans==-1){
            printf("lack of junxun\n");
        }else{
            printf("%d\n",ans);
        }
    }
}

问题 B: 不高兴的津津
题目描述

津津上初中了。妈妈认为津津应该更加用功学习,所以津津除了上学之外,还要参加妈妈为她报名的各科复习班。另外每周妈妈还会送她去学习朗诵、舞蹈和钢琴。但是津津如果一天上课超过八个小时就会不高兴,而且上得越久就会越不高兴。假设津津不会因为其它事不高兴,并且她的不高兴不会持续到第二天。请你帮忙检查一下津津下周的日程安排,看看下周她会不会不高兴;如果会的话,哪天最不高兴。

输入

输入包括七行数据,分别表示周一到周日的日程安排。每行包括两个小于10的非负整数,分别表示津津在学校上课的时间和妈妈安排她上课的时间。

输出

输出包括一行,这一行只包含一个数字。如果不会不高兴那么输出0,如果会那么输出最不高兴的是周几〔用1,2,3,4,5,6,7分别表示周一,周二,周三,周四,周五,周六,周日〕。如果有两天或两天以上不高兴的程度相当,那么输出时间最靠前的一天。

样例输入

53
62
72
53
54
04
06

样例输出

3

#include <bits/stdc++.h>
using namespace std;
const int maxn=1e3+5;
int main()
{
    int x,ans=0,ma=0;
    for(int i=1;i<=7;++i){
        scanf("%d",&x);
        if(x%10+x/10>8){
            if(ans==0||x%10+x/10>ma){
                ans=i;
                ma=x%10+x/10;
            }
        }
    }
    printf("%d\n",ans);
    return 0;
}

问题 C: 花生采摘
题目描述

鲁宾逊先生有一只宠物猴,名叫多多。这天,他们两个正沿着乡间小路散步,突然发现路边的告示牌上贴着一张小小的纸条:“欢迎免费品尝我种的花生!——熊字”。
鲁宾逊先生和多多都很开心,因为花生正是他们的最爱。在告示牌背后,路边真的有一块花生田,花生植株整齐地排列成矩形网格〔如图1〕。有经验的多多一眼就能看出,每棵花生植株下的花生有多少。为了训练多多的算术,鲁宾逊先生说:“你先找出花生最多的植株,去采摘它的花生;然后再找出剩下的植株里花生最多的,去采摘它的花生;依此类推,不过你一定要在我限定的时间内回到路边。”
我们假定多多在每个单位时间内,可以做以下四件事情中的一件:
1)从路边跳到最靠近路边〔即第一行〕的某棵花生植株;
2)从一棵植株跳到前后左右与之相邻的另一棵植株;
3)采摘一棵植株下的花生;
4)从最靠近路边〔即第一行〕的某棵花生植株跳回路边。
现在给定一块花生田的大小和花生的分布,请问在限定时间内,多多最多可以采到多少个花生?注意可能只有部分植株下面长有花生,假设这些植株下的花生个数各不相同。
例如在样例所示的花生田里,只有位于(2,5),(3,7),(4,2),(5,4)的植株下长有花生,个数分别为13,7,15,9。多多在21个单位时间内,最多可以采到37个花生。

输入

输入的第一行包括三个整数,M,N和K,用空格隔开;表示花生田的大小为M*N〔1<=M,N<=20〕,多多采花生的限定时间为K〔0<=K<=1000〕个单位时间。接下来的M行,每行包括N个非负整数,也用空格隔开;第i+1行的第j个整数Pij〔0<=Pij<=500〕表示花生田里植株(i,j)下花生的数目,0表示该植株下没有花生。

输出

输出包括一行,这一行只包含一个整数,即在限定时间内,多多最多可以采到花生的个数。

样例输入

6 7 21
0 0 0 0 0 0 0
0 0 0 0 13 0 0
0 0 0 0 0 0 7
0 15 0 0 0 0 0
0 0 0 9 0 0 0
0 0 0 0 0 0 0

样例输出

37

思路

将每一个株花生的坐标和花生数量用结构体储存,按花生数量降序排序。//题目要求按花生数量采摘
要考虑返回的时间,采摘一个花生的条件是采摘完它后还有时间返回路边

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cmath>
using namespace std;
int pic[50][50];
int ans,n,m,k,cnt,nowx,nowy,tot;
struct edge{
    int x,y,v;
}e[5000];
bool cmp(edge a,edge b){
    return a.v > b.v;
}
int main(){
    scanf("%d%d%d",&n,&m,&k);
    for(int i = 1; i<=n; i++){
        for(int j = 1; j<=m; j++){
            scanf("%d",&pic[i][j]);
            if(pic[i][j]){
                cnt ++;
                e[cnt].x = i;e[cnt].y =j;e[cnt].v = pic[i][j];
            }
        }
    } 
    sort(e+1,e+1+cnt,cmp);  
    if(2*e[1].y + 1 > k){
        printf("0\n");
        return 0;
    }
    nowy = e[1].y;
    for(int i = 1; i<=cnt; i++){
        tot += abs(nowy - e[i].y) + abs(nowx - e[i].x) + 1; 
        if(tot + e[i].x > k)break;
        nowx = e[i].x;
        nowy = e[i].y;
        ans += e[i].v; 
    }
    printf("%d\n",ans);      
    return 0;
}

问题 D: FBI树
题目描述

我们可以把由“0”和“1”组成的字符串分为三类:全“0”串称为B串,全“1”串称为I串,既含“0”又含“1”的串那么称为F串。
FBI树是一种二叉树[1],它的结点类型也包括F结点,B结点和I结点三种。由一个长度为2N的“01”串S可以构造出一棵FBI树T,递归的构造方法如下:
1)T的根结点为R,其类型与串S的类型相同;
2)假设串S的长度大于1,将串S从中间分开,分为等长的左右子串S1和S2;由左子串S1构造R的左子树T1,由右子串S2构造R的右子树T2。
现在给定一个长度为2N的“01”串,请用上述构造方法构造出一棵FBI树,并输出它的后序遍历序列[2]。

输入

第一行是一个整数N〔1<=N<=128〕,数据保证n为2的幂次方。
第二行是一个长度为2N的“01”串。

输出

输出包括一行,这一行只包含一个字符串,即FBI树的后序遍历序列。

样例输入

4
10001011

样例输出

IBFBBBFIBFIIIFF

提示

[1]二叉树:二叉树是结点的有限集合,这个集合或为空集,或由一个根结点和两棵不相交的二叉树组成。这两棵不相交的二叉树分别称为这个根结点的左子树和右子树。
[2]后序遍历:后序遍历是深度优先遍历二叉树的一种方法,它的递归定义是:先后序遍历左子树,再后序遍历右子树,最后访问根。

思路

递归建树,自底向上求出节点的类型
再后序遍历输出

#include <bits/stdc++.h>
using namespace std;
const int maxn=1e5+5;
struct node{
    int l,r;
    char v;
}tr[maxn];
char s[maxn];
void build(int e,int l,int r){
    tr[e].l=l,tr[e].r=r;
    if(l==r){
        tr[e].v=s[l]=='0'?'B':'I';
        return;
    }
    int mid=(l+r)>>1;
    build(e<<1,l,mid);
    build(e<<1|1,mid+1,r);
    if(tr[e<<1].v=='B'&&tr[e<<1|1].v=='B'){
        tr[e].v='B';
    }else if(tr[e<<1].v=='I'&&tr[e<<1|1].v=='I'){
        tr[e].v='I';
    }else{
        tr[e].v='F';
    }
}
void cout_(int e,int l,int r){
    if(l==r){
        printf("%c",tr[e].v);
        return;
    }
    int mid=(l+r)>>1;
    cout_(e<<1,l,mid);
    cout_(e<<1|1,mid+1,r);
    printf("%c",tr[e].v);
}
int main()
{
    int n;
    while(~scanf("%d %s",&n,s+1)){
        int ls=strlen(s+1);
        build(1,1,ls);
        cout_(1,1,ls);
        printf("\n");
    }
    return 0;
}

问题 E: 火星人
题目描述

人类终于登上了火星的土地并且见到了神秘的火星人。人类和火星人都无法理解对方的语言,但是我们的科学家发明了一种用数字交流的方法。这种交流方法是这样的,首先,火星人把一个非常大的数字告诉人类科学家,科学家破解这个数字的含义后,再把一个很小的数字加到这个大数上面,把结果告诉火星人,作为人类的回答。
火星人用一种非常简单的方式来表示数字——掰手指。火星人只有一只手,但这只手上有成千上万的手指,这些手指排成一列,分别编号为1,2,3……。火星人的任意两根手指都能随意交换位置,他们就是通过这方法计数的。
一个火星人用一个人类的手演示了如何用手指计数。如果把五根手指——拇指、食指、中指、无名指和小指分别编号为1,2,3,4和5,当它们按正常顺序排列时,形成了5位数12345,当你交换无名指和小指的位置时,会形成5位数12354,当你把五个手指的顺序完全颠倒时,会形成54321,在所有能够形成的120个5位数中,12345最小,它表示1;12354第二小,它表示2;54321最大,它表示120。下表展示了只有3根手指时能够形成的6个3位数和它们代表的数字:
三进制数
123
132
213
231
312
321
代表的数字
1
2
3
4
5
6
现在你有幸成为了第一个和火星人交流的地球人。一个火星人会让你看他的手指,科学家会告诉你要加上去的很小的数。你的任务是,把火星人用手指表示的数与科学家告诉你的数相加,并根据相加的结果改变火星人手指的排列顺序。输入数据保证这个结果不会超出火星人手指能表示的范围。

输入

输入包括三行,第一行有一个正整数N,表示火星人手指的数目〔1<=N<=10000〕。第二行是一个正整数M,表示要加上去的小整数〔1<=M<=100〕。下一行是1到N这N个整数的一个排列,用空格隔开,表示火星人手指的排列顺序。

输出

输出只有一行,这一行含有N个整数,表示改变后的火星人手指的排列顺序。每两个相邻的数中间用一个空格分开,不能有多余的空格。

样例输入

5
3
1 2 3 4 5

样例输出

1 2 4 5 3

思路

其实就是将输入的排列变成字典序在它后面第m个的排列
可以用next_permutation函数(将一个排列变成字典序在它后一个的排列)

#include <bits/stdc++.h>
using namespace std;
const int maxn=1e4+5;
int a[maxn];
int main()
{
    int n,m;
    while(~scanf("%d",&n)){
        scanf("%d",&m);
        for(int i=1;i<=n;++i){
            scanf("%d",&a[i]);
        }
        while(m--){
            next_permutation(a+1,a+n+1);
        }
        for(int i=1;i<=n;++i){
            printf("%d%c",a[i],i==n?'\n':' ');
        }
    }
    return 0;
}

问题 F: 小B旅游
题目描述

小B在一个有N个城市M条道路的国家,每条道路连接的城市可以互相到达且每条道路小B都要花1步去走过它。现在他在1号城市,问他走P步最多能走多少个不同的城市?

输入

输入格式:第1行,三个正整数N、M、P,意义如题:接下来M行,每行两个整数U、V,表示存在一条连接U、V的无向边。

输出

输出格式:1行,一个整数,表示从1号城市出发走P步的所有情况,共能经过多少个不同的城市。

样例输入

4 4 2
1 2
1 3
2 3
3 4

样例输出

4

提示

数据规模:
1<=N<=100000,1<=M<=5000000,1<=P<=10000

思路

bfs或者dfs
但是不能直接开那么大的数组,要用链式前向星或者vector

从1开始bfs,将遍历过的点标记

#include <bits/stdc++.h>
using namespace std;
const int maxn=1e7+5;
int n,m,p;
struct node{
    int x,step;
};
vector<int> w[100005];
int vis[100005],ans;
void bfs(){
    queue<node> pq;
    node now,ne;
    now.x=1,now.step=0;
    vis[1]=1;
    pq.push(now);
    while(!pq.empty()){
        now=pq.front(),pq.pop();
        for(int i=0;i<w[now.x].size();++i){
            ne.x=w[now.x][i],ne.step=now.step+1;
            if(vis[ne.x]==0&&ne.step>=0){
                ++ans;
                vis[ne.x]=1;
                pq.push(ne);
            }
        }
    }
}
int main()
{
    while(~scanf("%d %d %d",&n,&m,&p)){
        memset(vis,0,sizeof(vis));
        ans=1;
        for(int i=1;i<=m;++i){
            int a,b;
            scanf("%d %d",&a,&b);
            w[a].push_back(b);
            w[b].push_back(a);
        }
        bfs();
        printf("%d\n",ans);
    }
    return 0;
}

从1开始dfs,将遍历过的点标记
答案就是被标记的城市数
不过要注意一个特殊情况
在这里插入图片描述
所以标记的时候标记数组存的是步数…如代码中进行是否继续dfs的判断
dfs的前向星写法

#include <bits/stdc++.h>
using namespace std;
const int maxn=1e7+5;
int n,m,p;
struct node{
    int to,next;
}edge[maxn];
int head[100005],vis[100005],cnt,ans;
void dfs(int now,int num){
    if(vis[now]==0){
        ++ans;
    }
    vis[now]=num;
    if(num>p){
        return;
    }
    for(int i=head[now];i!=-1;i=edge[i].next){
        int to=edge[i].to;
        if(vis[to]==0||num+1<vis[to]){
            dfs(to,num+1);
        }
    }
}
void add(int a,int b){
    edge[++cnt].to=b;
    edge[cnt].next=head[a];
    head[a]=cnt;
}
int main()
{
    while(~scanf("%d %d %d",&n,&m,&p)){
        memset(vis,0,sizeof(vis));
        memset(head,-1,sizeof(head));
        cnt=ans=0;
        for(int i=1;i<=m;++i){
            int a,b;
            scanf("%d %d",&a,&b);
            add(a,b),add(b,a);
        }
        dfs(1,1);
        printf("%d\n",ans);
    }
    return 0;
}

dsf的vector写法

#include <bits/stdc++.h>
using namespace std;
const int maxn=1e7+5;
int n,m,p;
vector<int> w[100005];
int vis[100005],ans;
void dfs(int now,int num){
    if(vis[now]==0){
        ++ans;
    }
    vis[now]=num;
    if(num>p){
        return;
    }
    for(int i=0;i<w[now].size();++i){
        int to=w[now][i];
        if(vis[to]==0||num+1<vis[to]){
            dfs(to,num+1);
        }
    }
}
int main()
{
    while(~scanf("%d %d %d",&n,&m,&p)){
        memset(vis,0,sizeof(vis));
        ans=0;
        for(int i=1;i<=m;++i){
            int a,b;
            scanf("%d %d",&a,&b);
            w[a].push_back(b);
            w[b].push_back(a);
        }
        dfs(1,1);
        printf("%d\n",ans);
    }
    return 0;
}

问题 G: 括号匹配
题目描述

括号主要有:大括号“{ }”、中括号“[ ]”、小括号“( )”。给定一个只包含左右括号的合法括号序列(序列长度2<=n<=10000),按右括号从左到右的顺序输出每一对配对的括号出现的位置(括号序列以0开始编号)

输入

输入格式:仅1行,表一个合法的括号序列

输出

输出格式:设括号序列有n个右括号,每行两个整数l、r,表示配对的括号左括号出现在第l位,右括号出现在第r位。

样例输入

{()[()()]}()

样例输出

1 2
4 5
6 7
3 8
0 9
10 11

思路

用栈处理
从左到右遍历字符,如果和栈顶匹配,则出栈并输出对应的下标对,否则入栈

#include <bits/stdc++.h>
using namespace std;
const int maxn=1e5+5;
char s[maxn];
struct node{
    int id;
    char v;
};
int main()
{
    while(~scanf("%s",s)){
        stack<node> sta;
        int ls=strlen(s);
        node now;
        for(int i=0;i<ls;++i){
            now.id=i;
            if(s[i]=='(')now.v=')';
            if(s[i]=='{')now.v='}';
            if(s[i]=='[')now.v=']';
            if(!sta.empty()&&sta.top().v==s[i]){
                printf("%d %d\n",sta.top().id,i);
                sta.pop();
            }else{
                sta.push(now);
            }
        }
    }
    return 0;
}

问题 H: 报数游戏
题目描述

有n个小朋友,按顺时针方向围成一圈(编号从1—n),从第1号开始报数,一直数到m,数到m的小朋友退出圈外,剩下的小朋友再接着从1开始报数。

输入

T组数据,第一行为T(1<=T<=10)
接下来T行,每行用空格分开两个整数n、m(1<=m,n<=10000)

输出

输出T行
每行一个答案表示第1号小朋友退出前,报数为m的次数

样例输入

1
6 2

样例输出

4

思路

典型的约瑟夫环问题
数组暴力模拟需要移动的数太多,用数组标记进行计数也太耗时

链表模拟(这里是用数组模拟链表)

#include <bits/stdc++.h>
using namespace std;
const int maxn=1e5+5;
int next_[10005],pre[10005];
int main()
{
    int n,m,t;
    scanf("%d",&t);
    while(t--){
        scanf("%d %d",&n,&m);
        for(int i=1;i<=n;++i){
            next_[i]=i+1;
            pre[i]=i-1;
        }
        next_[n]=1,pre[1]=n;
        int ans=0,now=1;
        while(1){
            int x=m-1;
            while(x--){
                now=next_[now];
            }
            //cout<<now<<"---"<<endl;
            if(now==1)break;
            next_[pre[now]]=next_[now];
            pre[next_[now]]=pre[now];
            now=next_[now];
            ++ans;
        }
        printf("%d\n",ans);
    }
}

约瑟夫环问题递归解法解释1
约瑟夫环问题递归解法解释2

#include <bits/stdc++.h>
using namespace std;
const int maxn=1e5+5;
int dfs( int n, int m, int k)
{
    if(k==1)
        return(n+m-1) %n;
    else
        return(dfs(n-1,m,k-1)+m) %n;
}
int main()
{
    int n,m,t;
    scanf("%d",&t);
    while(t--){
        scanf("%d %d",&n,&m);
        for(int i=1;i<=n;++i){
            if(dfs(n,m,i)==0){
                printf("%d\n",i-1);
                break;
            }
        }
    }
}

问题 I: 小A的烦恼
题目描述

小A生活在一个神奇的国家,这个国家有N(N<=100000)个城市,还有M(M<=5000000)条道路连接两城市。道路连接的两个城市可以直接免费到达。小A比较烦恼,因为他想知道每个城市能直接到达哪些城市,你能帮帮他吗?保证每个城市都有道路与其连接。(注:按照输入的道路顺序输出每个城市直接连接的城市,若有城市出现多次,则按最小出现次序输出)

输入

第1行包含两个整数N和M;接下来M行,每行两个整数描述一条道路连接的两个城市的编号。

输出

输出N行,每行若干个用一个空格隔开的整数;第I行输出的是与城市I直接相连城市编号,保证城市的出现按照道路输入的先后顺序出现。

样例输入

4 5
2 3
3 1
1 4
2 4
1 2

样例输出

3 4 2
3 4 1
2 1
1 2

思路

用vector储存边的情况

因为可能有重边,需要用set或者map判断。而且还是多组输入

map

#include <bits/stdc++.h>
using namespace std;
const int maxn=1e5+5;
vector<int> w[maxn];
map<int,int> mp[maxn];
int main()
{
    int n,m;
    while(~scanf("%d %d",&n,&m)){
          
        for(int i=1;i<=m;++i){
            int a,b;
            scanf("%d %d",&a,&b);
            //if(a==b)
            //    continue;
            if(mp[a][b]==0)
                w[a].push_back(b),mp[a][b]=1;
            if(mp[b][a]==0)
                w[b].push_back(a),mp[b][a]=1;
        }
        for(int i=1;i<=n;++i){
            int l=w[i].size();
            if(l!=0)
                for(int j=0;j<l;++j){
                    printf("%d%c",w[i][j],j==l-1?'\n':' ');
                }
        }
        for(int i=1;i<=n;++i){
            w[i].clear();
            mp[i].clear();
        }
    }
}

set

#include <bits/stdc++.h>
using namespace std;
const int maxn=1e5+5;
vector<int> w[maxn];
set<int> se[maxn];
int main()
{
    int n,m;
    while(~scanf("%d %d",&n,&m)){
          
        for(int i=1;i<=m;++i){
            int a,b;
            scanf("%d %d",&a,&b);
            //if(a==b)
            //    continue;
            if(se[a].find(b)==se[a].end())
                w[a].push_back(b),se[a].insert(b);
            if(se[b].find(a)==se[b].end())
                w[b].push_back(a),se[b].insert(a);
        }
        for(int i=1;i<=n;++i){
            int l=w[i].size();
            if(l!=0)
                for(int j=0;j<l;++j){
                    printf("%d%c",w[i][j],j==l-1?'\n':' ');
                }
        }
        for(int i=1;i<=n;++i){
            w[i].clear();
            se[i].clear();
        }
    }
}

问题 J: 一步之遥
题目描述

小B在一个有N个城市M条道路的国家,每条道路连接的城市可以互相到达且每条道路都要花1步去走过它。现在他在P号城市,问有多少城市走1步能到达该城市?

输入

多组输入
第1行,三个正整数N、M、P,意义如题。
接下来M行,每行两个整数U、V,表示存在一条连接U、V的无向边。(0<=N<=1000000,0<=M<=500000)

输出

1行,走1步能到P城市的城市数量。

样例输入

4 4 1
1 2
1 3
2 3
3 4

样例输出

2

思路

map判断
不过可能有自环,自环也算一种情况

#include <bits/stdc++.h>
using namespace std;
const int maxn=1e5+5;
map<int,int> mp;
int main()
{
    int n,m,p;
    while(~scanf("%d %d %d",&n,&m,&p)){
        mp.clear();
        int ans=0;
        while(m--){
            int a,b;
            scanf("%d %d",&a,&b);
            if(a==p&&mp[b]==0){
                ++ans;
                mp[b]=1;
            }
            if(b==p&&mp[a]==0){
                ++ans;
                mp[a]=1;
            }
        }
        printf("%d\n",ans);
    }
}
  • 4
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值