选拔赛补题

我在选拔赛中做对了10道题,9和12没对,后面最难的3道题也没对,但是没有开放补题。

第9题

        这题是一个比较简单的图论题,关键在于题意的理解。朋友的朋友就是朋友,这意味着这张关系图中,假设标记为1的边为可行路径,那么在a和b没有直接敌对关系的情况下,只要a和b之间有可行路径,就说明a和b是朋友。但是题目中又说了a和b不能同时为朋友和敌人,所以如果a和b有敌对关系那么就不能是朋友了,这种情况就对应着“敌人,但有共同的朋友”。

        考虑到这题的数据量比较小,不易TLE和MLE,只需要对询问的数据进行搜索即可,因为同时需要dfs和查询直接关系,所以同时用邻接表和邻接矩阵存图比较好,和其他的dfs一样,因为避免出现成环时的死循环情况,必须要使用vis数组。

#include <bits/stdc++.h>
using namespace std;
int arr[105][105];  //图的顶点
bool vis[105];      //存放每个点是否被访问
typedef pair<int, int> node;
vector<node> vec[105];
bool dfs(int s, int e)  //友谊线能否到达对面
{
    bool ret = 0;
    if(s == e)
    {
        return 1;
    }
    for(auto x: vec[s])
    {
        int fir = x.first, sec = x.second;  //人和关系
        if(sec == 1 && !vis[fir])           //防止成环
        {
            vis[fir] = 1;
            ret = dfs(fir, e);
            vis[fir] = 0;
        }
    }
    return ret;
}
int main()
{
    int N, M, K;
    cin >> N >> M >> K;
    for(int i = 1; i <= M; ++i)
    {
        int a, b, c;
        cin >> a >> b >> c;
        vec[a].push_back(make_pair(b, c));
        vec[b].push_back(make_pair(a, c));
        arr[a][b] = arr[b][a] = c;
    }
    for(int i = 1; i <= K; ++i)
    {
        int a, b;
        cin >> a >> b;
        vis[a] = 1;
        bool f = dfs(a, b);
        vis[a] = 0;
        if(f)       //f不了就说明已经不是朋友了
        {
            if(arr[a][b] != -1)
            {
                cout << "No problem" << endl;
            }
            else
            {
                cout << "OK but..." << endl;
            }
        }
        else
        {
            if(arr[a][b] != -1)
            {
                cout << "OK" << endl;
            }
            else
            {
                cout << "No way" << endl;
            }
        }
    }
    return 0;
}

        此外我还有一种方法,我们不是学过弗洛伊德算法吗?还记得那三重循环吗?那我们就可以写出三重循环,通过这三重循环,一次加入一个点,判断每两个点之间是否有可行路径就可以了。这样子也不会遗漏。注意因为有朋友和敌人两种关系,所以要用两张图来分别存储“直接关系”和“是否有共同的朋友”两种关系就可以了。我正因为做的时候没考虑到这个所以就错了。看起来三重循环,实际上数据量小,不会超时,在询问量比较大的时候这种方法就会比较好了。这种办法比dfs的还要快呢!!!

#include <bits/stdc++.h>
using namespace std;
int n, m, k;
int arr[105][105], ak[105][105];
//arr用于存储两点间的直接关系,ak用于存储是否有共同的朋友
int main()
{
    cin >> n >> m >> k;
    for(int i = 1; i <= m; ++i)
    {
        int a, b, c;
        cin >> a >> b >> c;
        arr[a][b] = arr[b][a] = c;
        if(c != -1)
            ak[a][b] = ak[b][a] = c;
    }
    //类似弗洛伊德算法的思想,琼剧
    for(int t = 1; t <= n; ++t)
    {
        for(int i = 1; i <= n; ++i)
        {
            for(int j = 1; j <= n; ++j)
            {   //双向图不用害怕
                if(ak[i][t]==1 && ak[t][j]==1)
                {
                    ak[i][j] = 1;
                }
            }
        }
    }
    while(k--)
    {
        int a, b;
        cin >> a >> b;
        if(ak[a][b] == 1)
        {
            if(arr[a][b] >= 0)
            {
                cout << "No problem" << endl;
            }
            else
            {
                cout << "OK but..." << endl;
            }
        }
        else
        {
            if(arr[a][b] >= 0)
            {
                cout << "OK" << endl;
            }
            else
            {
                cout << "No way" << endl;
            }
        }
    }
    return 0;
}

第12题

 

 

        这题在第二组题中相对比较难一点,但是也是比较基础的题。这题考察的还是图论的基本知识和dfs递归查找。还有一个小技巧就是可以在dfs递归函数中额外添加一个参数来知道递归到了第几层,从而可以知道树/二叉树的深度。就是因为不会这个小技巧所以自己做的时候卡住。哦对了,输入一个人的父母id之后标记父母的性别。这是个隐含条件,我当时自作聪明没有标记结果错了就不知道哪里有问题。

#include <bits/stdc++.h>
using namespace std;
const int maxn = 1E5+9;
struct person{
    char sex;
    int fa;
    int ma;
} arr[maxn];
int vis[maxn];
int flag = 1;
void dfs(int f, int d)      //起始下标
{
    if(f >= 1 && d <= 5)
    {
        if(!vis[f])
        {
            vis[f] = 1;
            dfs(arr[f].fa, d+1);
            dfs(arr[f].ma, d+1);
        }
        else
        {
            flag = 0;
        }
    }
}
int find(int a, int b)
{
    if(arr[a].sex == arr[b].sex)
    {
        return -1;
    }
    else    //需要bfs
    {
        memset(vis, 0, sizeof(vis));
        flag = 1;
        dfs(a, 1), dfs(b, 1);
        return flag;
    }
}
int main()
{
    int n;
    cin >> n;
    for(int i = 1; i <= n; ++i)
    {
        int a, b, c;
        char d;
        cin >> a >> d >> b >> c;
        arr[a] = {d, b, c};
        if(b != -1)
        {
            arr[b].sex = 'M';       //隐含条件
        }
        if(c != -1)
        {
            arr[c].sex = 'F';       //隐含条件
        }
    }
    int q;
    cin >> q;
    while(q--)
    {
        int a, b;
        cin >> a >> b;
        switch(find(a, b))
        {
            case -1:
                cout << "Never Mind" << endl;
                break;
            case 0:
                cout << "No" << endl;
                break;
            case 1:
                cout << "Yes" << endl;
                break;
        }
    }
    return 0;
}

还有几个因为错误罚时的题,这里我也写出来。

第六题

         真没想到自己在hello world级别的题上面还能犯错。首先string类的substr函数常用第一个参数是开始的下标,第二个参数是字串的长度。其次这道题只说了A和B在1-1000之间,并没有说结果也一定在1-1000之间。到底还是语文限制了我的学习。

#include <bits/stdc++.h>
using namespace std;
void printnum(int v, int l, int r)
{
    if(v >= l && v <= r)
    {
        printf("%d", v);
    }
    else{
        putchar('?');
    }
}
int main(){
    string str, a, b;
    getline(cin, str);
    int s, len = str.length();
    for(s = 0; s < len; ++s)
    {
        if(str[s] == ' ')
        {
            break;
        }
    }
    a = str.substr(0, s), b = str.substr(s+1);
//     cout << a << "_" << b << endl;
    int va=0, vb=0;
    for(auto x:a)
    {
        if(isdigit(x))
        {
            va = va*10+x-'0';
        }
        else
        {
            va = 0;
            break;
        }
    }
    for(auto x:b)
    {
        if(isdigit(x))
        {
            vb = vb*10+x-'0';
        }
        else
        {
            vb = 0;
            break;
        }
    }
    int vc;
    if(va > 0 && va < 1001 && vb > 0 && vb < 1001)
    {
        vc = va+vb;
    }
    else{
        vc = 0;
    }
    printnum(va, 1, 1000), printf(" + "), printnum(vb, 1, 1000),
    printf(" = "), printnum(vc, 1, INT_MAX);
    return 0;
}

第十题

 

         这题被罚时五次。首先就是一个sort函数的使用排序题。按字母序排序是啥意思?其实只要字符串比较大小就可以。还有的成绩>=60就可以及格,不是>60,而且选入名人堂的人不一定成绩都及格了,有可能是瘸子里面挑将军的。又是语文限制了我的学习,梅开二度。

#include <bits/stdc++.h>
using namespace std;
int n, g, k, sum;
struct stu
{
    int first;
    string second;
};
int main()
{
    cin >> n >> g >> k;
    vector<stu> arr(n+1);
    for(int i = 1; i <= n; ++i)
    {
        cin >> arr[i].second >> arr[i].first;
        if(arr[i].first >= g)
        {
            sum += 50;
        }
        else if(arr[i].first >= 60)
        {
            sum += 20;
        }
    }
    cout << sum << endl;
    sort(arr.begin()+1, arr.end(), [](const stu&s1, const stu&s2)
    {
        if(s1.first != s2.first)
        {
            return s1.first > s2.first;
        }
        else
        {
            return s1.second < s2.second;
        }
    });
    for(int i = 1, j = 1; ; i++)
    {
        if(arr[i].first == arr[j].first)
        {
        }
        else
        {
            j = i;
        }
        if(j > k)
        {
            break;
        }
        cout << j << ' ' << arr[i].second << ' ' << arr[i].first << endl;
    }
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值