NEU winter_training 2

之前教练让我写这个的题解
顺便复制过来水一发博客

7-1 到底有多二

题解

数字位数很长,于是把数字以字符串的形式读进来,数2的个数,再额外特判是否负数和偶数。

代码

#include<iostream>
#include<cstdio>
#include<ctype.h>
using namespace std;
string s;
double ans;
int main(){
    cin>>s;
    int len=s.size();
    for(int i=0;i<len;++i){
        if(isdigit(s[i]) && s[i]=='2')ans+=1;
    }
    if(s[0]=='-')ans=ans*1.5/(len-1);
    else ans/=len;
    if(s[len-1]%2==0)ans*=2;
    printf("%.2f%%",ans*100);
    return 0;
}

7-2 大笨钟

题解

读懂题然后根据题意分类讨论即可。

12:00及之前都是不敲钟的,非整点的时候会比整点多敲一下钟。

代码

#include<iostream>
#include<cstdio>
using namespace std;

int h,m;
int main(){
    scanf("%d:%d",&h,&m);
    if(h<12 || h==12 && m==0)printf("Only %02d:%02d.  Too early to Dang.",h,m);
    else {
        if(m)for(int i=13;i<=h+1;++i)printf("Dang");
        else for(int i=13;i<=h;++i)printf("Dang");
    }
    return 0;
}

7-3 谁先倒

题解

依旧是根据题意模拟,记录两个人喝酒的杯数,其中一个超过上限时结束循环。

代码

#include<iostream>
#include<cstdio>
#include<cstdlib>
int a,b,A,B,n;
using namespace std;
int main(){
    scanf("%d%d%d",&A,&B,&n);
    for(int i=1;i<=n;++i){
        int x,y,z,w;
        scanf("%d%d%d%d",&x,&y,&z,&w);
        if(x+z==y && x+z!=w)++a;
        if(x+z!=y && x+z==w)++b;
        if(a>A){printf("A\n%d",b);break;}
        if(b>B){printf("B\n%d",a);break;}
    }
    return 0;
} 

7-4 帅到没朋友

题解

比起前边的题,是个稍微大了一点的模拟……

存储每个朋友圈去重后的人数(siz),以及每个人属于哪几个朋友圈(bel)

然后对于每个查询的人(注意去重),检查这个人所在的朋友圈及人数来确定他是否太帅

代码

#include<cstdio>
#include<algorithm>
using namespace std;

const int N=101;
const int ID=100000;
int n,m,a[1001];
int cnt[ID],bel[ID][N],siz[N];
bool ask[10001],handsome;
int ans[ID],cntans;
int main(){
    scanf("%d",&n);
    for(int i=1;i<=n;++i){
        int k;scanf("%d",&k);
        for(int j=1;j<=k;++j)
        scanf("%d",&a[j]);
        sort(a+1,a+k+1);
        unique(a+1,a+k+1);//去重 
        for(int j=1;j<=k;++j){
            bel[ a[j] ][ ++cnt[a[j]] ]=i;//a[j]属于朋友圈i,cnt记录这个人属于几个朋友圈
            ++siz[i];//该朋友圈的人数
        }
    }
    scanf("%d",&m);
    for(int i=1;i<=m;++i){
        int pos;scanf("%d",&pos);
        if(ask[pos]==1)continue;//查询多次只输出一次
        ask[pos]=1;
        bool ishandsome=1;//这个人是否有朋友
        for(int i=1;i<=cnt[pos];++i){
            if(siz[ bel[pos][i] ]>1)ishandsome=0;
        }
        if(ishandsome){
            ans[++cntans]=pos;
            handsome=1;//是否有人太帅
        }
    }
    if(!handsome)printf("No one is handsome");
    else{
        for(int i=1;i<=cntans;++i){
            printf("%05d",ans[i]);
            if(i<cntans)printf(" ");
        }
    }   
    return 0;
}

7-5 重要的话说三遍

题解

\I'm gonna WIN!/ \I'm gonna WIN!/ \I'm gonna WIN!/

……这个我实在不知道该写点什么好qwq。

代码

#include<cstdio>

int main(){
    printf("I'm gonna WIN!\n");
    printf("I'm gonna WIN!\n");
    printf("I'm gonna WIN!");
    return 0;
}

7-6 奇偶分家

题解

%2为0则为偶数,为1则为奇数。

代码

#include<stdio.h>

int n,odd,eve;
int main(){
    scanf("%d",&n);
    for(int i=1;i<=n;++i){
        int x;scanf("%d",&x);
        if(x%2)++odd;
        else ++eve; 
    }
    printf("%d %d",odd,eve);
    return 0;
}

7-7 输出GPLT

题解

用四个变量分别计G、P、L、T的个数,再按规定顺序循环输出即可。

代码

#include<stdio.h>
#include<string.h>

char s[10009]; 
int g,p,l,t;
int main(){
    scanf("%s",s);
    g=p=l=t=0;
    int len=strlen(s);
    for(int i=0;i<len;++i){
        if(s[i]>='a' && s[i]<='z')s[i]-='a'-'A';
        if(s[i]=='G')++g;
        if(s[i]=='P')++p;
        if(s[i]=='L')++l;
        if(s[i]=='T')++t;
    }
    while(g+p+l+t){
        if(g){--g;printf("G");}
        if(p){--p;printf("P");}
        if(l){--l;printf("L");}
        if(t){--t;printf("T");}
    }
    printf("\n");
    return 0;
}

7-8 后天

题解

七天一循环可以通过%7来实现

不过条件是星期要用0~6来表示

可以通过-1再+1达到这个效果

代码

#include<stdio.h>

int main(){
    int d;scanf("%d",&d);
    d=((d+2)-1)%7+1;
    printf("%d\n",d);
    return 0;
}

7-9 抢红包

题解

又是一道模拟

对于每个红包,抢的人加钱数,发的人减钱数

排序按照三个条件依次排

代码

#include<iostream>
#include<cstdio>
#include<algorithm>
const int N=10001;
using namespace std;
struct node{
    int id,money,cnt;
    bool operator < (const node& b) const {
        if(money!=b.money)return money>b.money;//钱数优先
        else if(cnt!=b.cnt)return cnt>b.cnt;//红包数第二
        else return id<b.id;//还相等的看id
        
    } 
}per[N];
int main(){
    int n;scanf("%d",&n);
    for(int i=1;i<=n;++i){
        per[i].id=i;
        int k;scanf("%d",&k);
        for(int j=1;j<=k;++j){
            int p,m;scanf("%d%d",&p,&m);
            ++per[p].cnt;
            per[p].money+=m;//抢红包的
            per[i].money-=m;//发红包的
        }
    }
    sort(per+1,per+n+1);
    for(int i=1;i<=n;++i){
        printf("%d %.2lf",per[i].id,(double)per[i].money/100);
        if(i<n)printf("\n");
    }
    return 0;
}

7-10 排座位

题解

用了两个邻接矩阵存储宾客之间的关系

一个类似floyd的三重循环扩散朋友关系(若ik是朋友,kj是朋友,那么ij也是朋友)

代码

#include<iostream>
#include<cstdio>
#include<ctype.h>
using namespace std;
bool suki[101][101],kirai[101][101];
int n,m,K;
int main(){
    scanf("%d%d%d",&n,&m,&K);
    for(int i=1;i<=m;++i){
        int a,b,f;scanf("%d%d%d",&a,&b,&f);
        if(f==1)suki[a][b]=suki[b][a]=1;//朋友关系
        else kirai[a][b]=kirai[b][a]=1;//敌人关系
    }
    for(int i=1;i<=n;++i)
    for(int j=1;j<=n;++j)
    for(int k=1;k<=n;++k)
        suki[i][j]|=suki[i][k]&suki[k][j];//扩散朋友关系
    for(int i=1;i<=K;++i){
        int a,b;scanf("%d%d",&a,&b);
        if( suki[a][b] && !kirai[a][b])printf("No problem");
        if(!suki[a][b] && !kirai[a][b])printf("OK");
        if( suki[a][b] &&  kirai[a][b])printf("OK but...");
        if(!suki[a][b] &&  kirai[a][b])printf("No way");
        if(i<K)printf("\n");
    }
    return 0;
}

7-11 玩转二叉树

题解

根据前序遍历和中序遍历求树的结构的部分和第一场中的7-10 树的遍历 相似,区别在于后序遍历根在最后,前序遍历根在最前
按层序输出部分依旧采用BFS
将树镜面翻转的部分,可以存树的时候反着存,也可以输出的时候反着输出

代码

#include<cstdio>
#include<cstdlib>
#include<queue>
using namespace std;
const int N=301;
int n,pre[N],in[N];//前序遍历和中序遍历
int root,ls[N],rs[N];
int work(int lp,int rp,int li,int ri){//前序遍历和中序遍历的边界
    if(li==ri)return in[ri];
    int rt=pre[lp];//这棵子树的根
    int k=li;while(in[k]!=rt)++k;//找到它在中序遍历中的位置
    int lenl=k-li;
    if(li<k)ls[rt]=work(lp+1,lp+lenl,li,k-1);
    if(k<ri)rs[rt]=work(lp+1+lenl,rp,k+1,ri);
    return rt;
}
queue<int>q;
void print(){//BFS输出层序遍历
    while(!q.empty()){
        int x=q.front();q.pop();
        printf("%d",x);
        if(rs[x])q.push(rs[x]);//先输出右子树
        if(ls[x])q.push(ls[x]);//再输出左子树
        if(!q.empty())printf(" ");
    }
}
int main(){
    scanf("%d",&n);
    for(int i=1;i<=n;++i)scanf("%d",&in[i]);//中序遍历
    for(int i=1;i<=n;++i)scanf("%d",&pre[i]);//前序遍历
    root=work(1,n,1,n);
    q.push(root);
    print();
    return 0;
}

7-12 关于堆的判断

题解

一道堆的模板题。

依次把每个数插到末尾,逐层向上调整维护之类的堆的基本操作就不再赘述了

用了一个map(M)记录每个数在堆里的位置

以及这个题的读入比较麻烦需要注意

代码

#include<iostream> 
#include<cstdio>
#include<algorithm>
#include<ctype.h>
#include<map>
using namespace std;
const int N=1009;
int x,y,n,m,h[N],heap_size;
string s;
map<int,int>M;//每个数在堆里的位置
void insert(int k,int val){//堆的插入操作
    while(k>1 && h[k/2]>h[k]){
        swap(M[h[k]],M[h[k/2]]);
        swap(h[k],h[k/2]);
        k/=2;
    }
}
int poi;
inline int qread(){//从命题里读取数字
    int an=0,f=1;
    while(s[poi]<'0'||s[poi]>'9'){if(s[poi]=='-')f=-1;++poi;}
    while(s[poi]<='9'&&s[poi]>='0'){an=an*10+(s[poi]^48);++poi;}
    return an*f;
}
int judge(){//判断命题类型
    int len=s.size();
    for(int i=0;i<len;++i){
        if(s[i]=='b')return 2;
        if(s[i]=='p')return 3;
        if(s[i]=='c')return 4;
    }
    return 1;
}
int main(){
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;++i){
        scanf("%d",&h[i]);
        M[h[i]]=++heap_size;
        insert(i,h[i]);
    }
    getchar();
    for(int i=1;i<=m;++i){
        getline(cin,s);
        int flag=judge();
        poi=0;x=qread();if(flag>1)y=qread();
        x=M[x],y=M[y];
        switch(flag){
            case 1://为根
                if(x==1)printf("T");
                else printf("F");
                break;
            case 2://为兄弟节点
                if(x/2==y/2)printf("T");//父节点相同
                else printf("F");
                break;
            case 3:
                if(y/2==x)printf("T");
                else printf("F");
                break;
            case 4:
                if(x/2==y)printf("T");
                else printf("F");
                break;
        }
        if(i<m)printf("\n");
    }
    return 0;
}

7-13 天梯地图

题解

一道最短路题。

每条边有两个权值,按两个权值分别跑最短路,spfa或者dijkstra都可以(dijkstra更长)

注意同时间到达取最短,同距离取节点最少,两个条件不一样

fa数组用来存储路径中每个点的上一个结点,跑完最短路后从终点反向搜一遍得出路径

特判两条路径相等的情况

以及因为这道题的点标号是0~n-1,在输入输出的部分做了点手脚让它变成1~n

代码

#include<iostream>
#include<cstdio>
#include<cstring>
#include<queue>
using namespace std;
const int N=509;
int n,m,s,t;
int p[N],cnt;
struct edge{int to,nex,dis,tim;}e[N*N<<1];
void add(int u,int v,int dis,int tim){
    e[++cnt]=(edge){v,p[u],dis,tim};
    p[u]=cnt; 
}
int dis[N],tim[N],fa1[N],fa2[N];
int ans1[N],cnt1,ans2[N],cnt2;
bool in[N];
queue<int>q; 
inline int spfa1(int s)//最快
{
    memset(dis,0x3f,sizeof(dis));//距离
    memset(tim,0x3f,sizeof(tim));//时间
    memset(in,0,sizeof(in));
    q.push(s);tim[s]=dis[s]=0;in[s]=1;
    while(!q.empty())
    {
        int x=q.front();q.pop();in[x]=0;
        for(int i=p[x];i;i=e[i].nex)
        {
            int v=e[i].to;
            if(tim[v]==tim[x]+e[i].tim && dis[v]>dis[x]+e[i].dis){//相同时间取最短
                dis[v]=dis[x]+e[i].dis;
                fa1[v]=x;
                if(!in[v]){in[v]=1;q.push(v);}
            }
            if(tim[v]>tim[x]+e[i].tim)
            {
                tim[v]=tim[x]+e[i].tim;
                dis[v]=dis[x]+e[i].dis;
                fa1[v]=x;
                if(!in[v]){in[v]=1;q.push(v);}
            }
        }
    }
    return tim[t];
}
inline int spfa2(int s)//最短
{
    memset(dis,0x3f,sizeof(dis));//距离
    memset(tim,0x3f,sizeof(tim));//节点数(废数组利用系列)
    memset(in,0,sizeof(in));
    q.push(s);tim[s]=dis[s]=0;in[s]=1;
    while(!q.empty())
    {
        int x=q.front();q.pop();in[x]=0;
        for(int i=p[x];i;i=e[i].nex)
        {
            int v=e[i].to;
            if(dis[v]==dis[x]+e[i].dis && tim[v]>tim[x]+1){//相同距离取节点最少
                tim[v]=tim[x]+1;
                fa2[v]=x;
                if(!in[v]){in[v]=1;q.push(v);}
            }
            if(dis[v]>dis[x]+e[i].dis)
            {
                tim[v]=tim[x]+1;
                dis[v]=dis[x]+e[i].dis;
                fa2[v]=x;
                if(!in[v]){in[v]=1;q.push(v);}
            }
        }
    }
    return dis[t];
}
int main(){
    scanf("%d%d",&n,&m);
    for(int i=1;i<=m;++i){
        int u,v,type,val1,val2;
        scanf("%d%d%d%d%d",&u,&v,&type,&val1,&val2);
        add(u+1,v+1,val1,val2);if(!type)add(v+1,u+1,val1,val2);
    }
    scanf("%d%d",&s,&t);++s,++t;
    ans1[0]=spfa1(s);//最少的时间
    for(int x=t;x;x=fa1[x])ans1[++cnt1]=x-1;
    ans2[0]=spfa2(s);//最短的距离
    for(int x=t;x;x=fa2[x])ans2[++cnt2]=x-1;
    bool eq=1;//两路径是否相同
    if(cnt1!=cnt2)eq=0;
    for(int i=1;eq && i<=cnt1;++i)if(ans1[i]!=ans2[i])eq=0;
    if(eq){
        printf("Time = %d; Distance = %d: ",ans1[0],ans2[0]);
        for(int i=cnt1;i;--i){printf("%d",ans1[i]);if(i>1)printf(" => ");}
    }
    else{
        printf("Time = %d: ",ans1[0]);
        for(int i=cnt1;i;--i){printf("%d",ans1[i]);if(i>1)printf(" => ");}
        printf("\n");
        printf("Distance = %d: ",ans2[0]);
        for(int i=cnt2;i;--i){printf("%d",ans2[i]);if(i>1)printf(" => ");}
    }
    return 0;
} 

7-14 喊山

题解

BFS。

因为每两个山头距离为1,于是对于每个查询的山头,从该山头出发向四周BFS即可。

代码

#include<iostream>
#include<cstdio>
#include<queue>
#include<cstring>
using namespace std;
const int N=100001;
struct edge{int to,nex;}e[N<<2];
int p[N],cnt;
void add(int u,int v){
    e[++cnt]=(edge){v,p[u]};
    p[u]=cnt;
}
struct node{
    int id,dis;
};
int n,m,k,ans,maxdis;
queue<node>q;
int dis[N];
void bfs(int s){
    memset(dis,0,sizeof(dis));
    while(!q.empty())q.pop();
    ans=0;maxdis=1;dis[s]=1;
    q.push((node){s,1});
    while(!q.empty()){
        node cur=q.front();q.pop();
        int u=cur.id;
        if(dis[u]==maxdis)ans=min(ans,u);//距离相同取编号最小
        if(dis[u]>maxdis)maxdis=dis[u],ans=u;
        for(int i=p[u];i;i=e[i].nex){
            int v=e[i].to;if(dis[v])continue;
            dis[v]=dis[u]+1;
            q.push((node){v,dis[v]});
        }
    }
}
int main(){
    scanf("%d%d%d",&n,&m,&k);
    for(int i=1;i<=m;++i){
        int u,v;scanf("%d%d",&u,&v);
        add(u,v);add(v,u);
    }
    for(int i=1;i<=k;++i){
        int s;scanf("%d",&s);
        bfs(s);
        printf("%d",ans);
        if(i<k)printf("\n");
    }
    return 0;
} 

猜你喜欢

转载自www.cnblogs.com/wypx/p/12287519.html