天梯赛L2练习集

L2-001 紧急救援

朴素dijkstra

求最短路及对应路径,最短路长度最短即时间最短,时间相同的情况下召集的人最多

#include <iostream>
#include <cstring>
#include <vector>
using namespace std;
const int N = 510;
int g[N][N];
bool st[N]; 
// 结点人数 最短路径长度 召集最多人 路径条数 结点的pre
int w[N], d[N], va[N], cnt[N], path[N];
int n, m, s, D;
void dijkstra()
{
    memset(d, 0x3f, sizeof d);
    d[s] = 0;
    for(int i = 0; i < n; i ++)va[i] = w[i];
    cnt[s] = 1;
    
    for(int k = 0; k < n - 1; k ++)
    {
        int t = -1;
        for(int i = 0; i < n; i ++)
            if(!st[i] && (t == -1 || d[t] > d[i]))t = i;
        st[t] = true;

        for(int i = 0; i < n; i ++)
        {
            if(d[i] > d[t] + g[t][i])
            {
                d[i] = d[t] + g[t][i];
                cnt[i] = cnt[t];
                va[i] = va[t] + w[i];
                path[i] = t;
            }
            else if(d[i] == d[t] + g[t][i])
            {
                cnt[i] += cnt[t];
                if(va[i] < va[t] + w[i])
                {
                    va[i] = va[t] + w[i];
                    path[i] = t;
                }
            }
        }
    }
}
int main()
{
    cin>>n>>m>>s>>D;
    for(int i = 0; i < n; i ++)
    {
        cin>>w[i];
    }
    memset(g, 0x3f, sizeof g);
    while(m --)
    {
        int a, b, c;cin>>a>>b>>c;
        g[a][b] = g[b][a] = c;
    }
    dijkstra();
    cout<<cnt[D]<<' '<<va[D]<<endl;
    vector<int>v;
    int id = D;
    while(id != s)
    {
        v.push_back(id);
        id = path[id];
    }
    cout<<s;
    for(int i = v.size() - 1; i >= 0; i --)cout<<' '<<v[i];
    return 0;
}

L2-002 链表去重

小模拟

先把原链表构建起来,用两个数组即可,一个指针指向指针的,另一个指针指向值的

然后从前往后遍历判重,构建两个新链表

#include <bits/stdc++.h>
using namespace std;
const int N = 1e6 + 10;
int ne[N];
int e[N];
bool st[N];
int main()
{
    int s, n;cin>>s>>n;
    while(n --)
    {
        int a, b, c;cin>>a>>b>>c;
        ne[a] = c;
        e[a] = b;
    }
    vector<int> list1, list2;
    while(s != -1)
    {
        int j = e[s];
        if(st[abs(j)])list2.push_back(s);
        else list1.push_back(s);
        st[abs(j)] = true;
        s = ne[s];
    }
    for(int i = 0; i < list1.size(); i ++)
    {
        if(i == list1.size() - 1)
            printf("%05d %d %d\n", list1[i], e[list1[i]], -1);
        else printf("%05d %d %05d\n", list1[i], e[list1[i]], list1[i + 1]);
    }
    for(int i = 0; i < list2.size(); i ++)
    {
        if(i == list2.size() - 1)
            printf("%05d %d %d", list2[i], e[list2[i]], -1);
        else printf("%05d %d %05d\n", list2[i], e[list2[i]], list2[i + 1]);
    }
    return 0;
}

L2-003 月饼

结构体排序

按照价值从大到小排序,然后从前往后一个一个用直到用光需求量

#include <iostream>
#include <algorithm>
using namespace std;
const int N = 1010;
struct node
{
    double num, sum;
    double val;
    bool operator < (const node &W )
    {
        return val > W.val;
    }
}nd[N];

int main()
{
    int n;
    double m;cin>>n>>m;
    for(int i = 0; i < n; i ++)
        cin>>nd[i].num;
    for(int i = 0; i < n; i ++)
    {
        double sum;cin>>sum;
        nd[i].sum = sum;
        nd[i].val = 1.0 * sum / nd[i].num;
    }
    sort(nd, nd + n);

    double ans = 0;
    for(int i = 0; i < n; i ++)
    {
        double num = nd[i].num;
        double val = nd[i].val;
        if(m > num)ans += nd[i].sum, m -= num;
        else 
        {
            ans += val * m;
            break;
        }
    }
    printf("%.2f", ans);
    return 0;
}

L2-004 这是二叉搜索树吗?

数据结构

先判断是否二叉搜索树,再判断是否镜像

有个坑点就是这个输出树说的是

如果输入序列是对一棵二叉搜索树或其镜像进行前序遍历的结果,则首先在一行中输出 YES ,然后在下一行输出该树后序遍历的结果。

明显就有歧义,如果是镜像,那我输出镜像还是二叉搜索树?

#include <iostream>
#include <vector>
using namespace std;
int a[1010];
vector<int>v;
bool flag = false;

void find(int l, int r)
{
    if(l > r)return ;
    if(l == r)
    {
        v.push_back(a[l]);
        return ;
    }
    int i = l + 1, j = r;
    if(flag)
    {
        while(i <= r && a[i] < a[l])i++;
        while(j > l && a[j] >= a[l])j --;
    }
    else
    {
        while(i <= r && a[i] >= a[l])i ++;
        while(j > l && a[j] < a[l])j --;
    }
    if(i != j + 1)return ;
    find(l + 1, j), find(i, r);
    v.push_back(a[l]);
}

int main()
{
    int n;cin>>n;
    for(int i = 0; i < n; i ++)cin>>a[i];
    find(0, n - 1);
    if(v.size() == n)
    {
        cout<<"YES"<<endl;
        for(int i = 0; i < n; i ++)
        {
            if(i)cout<<' ';
            cout<<v[i];
        }
    }
    else
    {
        v.clear();
        flag = true;
        find(0, n - 1);
        if(v.size() == n)
        {
            cout<<"YES"<<endl;
            for(int i = 0; i < n; i ++)
            {
                if(i)cout<<' ';
                cout<<v[i];
            }
        }
        else cout<<"NO";
    }
    return 0;
}

L2-005 集合相似度

STL库 的set

#include<iostream>
#include <set>
using namespace std;
set<int> s[55];
int main()
{
    int n;cin>>n;
    for(int i = 1; i <= n; i ++)
    {
        int m;cin>>m;
        while(m --)
        {
            int x;cin>>x;
            s[i].insert(x);
        }
    }
    int m;cin>>m;
    while(m --)
    {
        int a, b;cin>>a>>b;
        int cnt = 0;
        for(auto i : s[a])
            if(s[b].count(i))cnt ++;
        int sum = s[a].size() + s[b].size() - cnt;
        printf("%.2f%%\n", 100.0 * cnt / sum);
    }
    return 0;
}

L2-006 树的遍历

数据结构

递归遍历将结点放到一个数组里然后输出

#include <iostream>
#include <map>
using namespace std;
int h[31], m[31];
map<int, int> mp;

void dfs(int hl, int hr, int ml, int mr, int idx)
{
    if(hl > hr || ml > mr)return ;
    mp[idx] = h[hr];// 根
    int id = ml;
    while(m[id] != h[hr])id ++; // 找根在中序的位置
     dfs(hl, hl + id - 1 - ml, ml, id - 1, idx * 2);
    dfs(hl + id - ml, hr - 1, id + 1, mr, idx * 2 + 1);
}

int main()
{
    int n;cin>>n;
    for(int i = 0; i < n; i ++)cin>>h[i];
    for(int i = 0; i < n; i ++)cin>>m[i];
    dfs(0, n - 1, 0, n - 1, 1);
    for(auto i = mp.begin(); i != mp.end(); i ++)
    {
        if(i != mp.begin())cout<<' ';
        cout<<i -> second;
    }
    return 0;
}

L2-007 家庭房产

并查集 自定义排序

先统计一个个家族的信息,根节点给最小的编号,记录每个家族的总人数和房子总面积,排序

#include <bits/stdc++.h>
using namespace std;
const int N = 1e4 + 10;
int p[N], peo[N];
double cnt[N], area[N];
int ide[N];
int find(int x)
{
    if(p[x] != x)p[x] = find(p[x]);
    return p[x];
}
int main()
{
    for(int i = 0; i < N; i ++)p[i] = i, peo[i] = 1;//0结点占那么多分草泥马
    
    int n;cin>>n;
    for(int i = 0; i < n; i ++)
    {
        int id;cin>>id;ide[i] = id;
        int k = 2;
        while(k --)
        {
            int x;cin>>x;
            if(x != -1)
            {
                int a = find(id), b = find(x);
                if(a == b)continue;
                if(a < b)swap(a, b);
                p[a] = b;
                peo[b] += peo[a];
            }
        }
        cin>>k;
        while(k --)
        {
            int x;cin>>x;
            if(x != -1)
            {
                int a = find(id), b = find(x);
                if(a == b)continue;
                if(a < b)swap(a, b);
                p[a] = b;
                peo[b] += peo[a];
            }
        }
        cin>>cnt[id]>>area[id];
    }

    set<int> s;
    for(int i = 0; i < n; i ++)
    {
        int id = ide[i];
        int fa = find(id);
        s.insert(fa);
        if(id != fa)
        {
            cnt[fa] += cnt[id];
            area[fa] += area[id];
        }
    }
    
    n = s.size();
    cout<<n<<endl;
    vector<int> v;
    for(auto i : s)
    {
        v.push_back(i);
        cnt[i] = 1.0*cnt[i] / peo[i];
        area[i] = 1.0*area[i] / peo[i];
    }
    sort(v.begin(), v.end(), [&](int a, int b){
            if(area[a] != area[b])return area[a] > area[b];
            return a < b;
         });
    for(auto i : v)
        printf("%04d %d %.3f %.3f\n", i, peo[i], cnt[i], area[i]);
    
    return 0;
}

L2-008 最长对称子串

暴力枚举

遍历所有情况,以一个字符或两个字符为中心进行扩展,就是分奇偶串

#include <iostream>
using namespace std;

int main()
{
    string s;getline(cin, s);
    int n = s.size();
    int res = 0;
    for(int i = 0; i < n; i ++)
    {
        int l = i - 1, r = i + 1;
        int t = 1;
        while(l >= 0 && r < n && s[l] == s[r])t += 2, l --, r ++;
        res = max(res, t);

        l = i, r = i + 1;
        t = 0;
        while(l >= 0 && r < n && s[l] == s[r])t += 2, l --, r ++;
        res = max(res, t);
    }
    cout<<res;
    return 0;
}

L2-009 抢红包

自定义排序

记录交易流水:发的人扣钱,收的人加钱,加红包次数。

对1-n的排列按照钱大小、红包个数和编号优先级排序

#include <iostream>
using namespace std;

const int N = 1e4 + 10;
int p[N], cnt[N];
double m[N];

int main()
{
    int n;cin>>n;
    for(int i = 1; i <= n; i ++)p[i] = i;
    for(int i = 1; i <= n; i ++)
    {
        int k;cin>>k;
        while(k --)
        {
            int x;
            double y;cin>>x>>y;
            m[i] -= y;
            m[x] += y;
            cnt[x] ++;
        }
    }
    sort(p + 1, p + 1 + n, [&](int a, int b){
        if(m[a] != m[b])return m[a] > m[b];
        else if(cnt[a] != cnt[b])return cnt[a] > cnt[b];
        else return a < b;
    });
    for(int i = 1; i <= n; i ++)
    {
        int id = p[i];
        printf("%d %.2f\n", id, m[id] / 100);
    }
    return 0;
}

L2-010 排座位

并查集

敌人与敌人、敌人与朋友之间没什么必要关系,但是朋友的朋友就是朋友,那就将朋友与朋友组成朋友圈,敌人与敌人单独记录

#include <iostream>
using namespace std;
bool g[110][110];
int p[110];
int find(int x)
{
    if(p[x] != x)p[x] = find(p[x]);
    return p[x];
}

int main()
{
    int n, m, k;cin>>n>>m>>k;
    for(int i = 1; i <= n; i ++)p[i] = i;
    while(m --)
    {
        int a, b, c;cin>>a>>b>>c;
        if(c == 1)p[find(a)] = find(b);
        else g[a][b] = g[b][a] = true;
    }
    while(k --)
    {
        int a, b;cin>>a>>b;
        int pa = find(a), pb = find(b);
        if(pa == pb && !g[a][b])puts("No problem");
        else if(pa != pb && !g[a][b])puts("OK");
        else if(pa == pb && g[a][b])puts("OK but...");
        else puts("No way");
    }
    return 0;
}

L2-011 玩转二叉树

数据结构

#include <bits/stdc++.h>
using namespace std;

int m[33], q[33];
map<int, int> mp;

void dfs(int ql, int qr, int ml, int mr, int idx)
{
    if(ql > qr || ml > mr)return ;
    mp[idx] = q[ql];
    int l = ml;
    while(m[l] != q[ql])l ++;// 找中序的根
    //先右再左就是镜面反转
    dfs(ql + 1, ql + 1 + l - ml - 1, ml, l - 1, idx * 2 + 1);
    dfs(ql + 1 + l - ml, qr, l + 1, mr, idx * 2);
}

int main()
{
    int n;cin>>n;
    for(int i = 1; i <= n; i ++)cin>>m[i];
    for(int i = 1; i <= n; i ++)cin>>q[i];
    dfs(1, n, 1, n, 1);

    for(auto i = mp.begin(); i != mp.end(); i ++)
    {
        if(i != mp.begin())cout<<' ';
        cout<<i -> second;
    }
    return 0;
}

L2-012 关于堆的判断

数据结构

手动建小根堆堆

#include <iostream>
using namespace std;
const int N = 1010;
int h[N];
int n, m;
void up(int u)
{
    if(u > 1 && h[u] < h[u / 2])
    {
        swap(h[u], h[u / 2]);
        up(u / 2);
    }
}

int find(int u,int x)
{
    if(u>n || h[u]>x)return -1;
    if(h[u]==x)return u;
    return max(find(u*2,x),find(u*2+1,x));
}

int main()
{
    cin>>n>>m;
    for(int i = 1; i <= n; i ++)
    {
        cin>>h[i];
        up(i);
    }

    while(m --)
    {
        int a;cin>>a;
        int u1 = find(1, a);
        string s;cin>>s;
        if(s == "is")
        {
            cin>>s;
            if(s == "the")
            {
                cin>>s;
                if(s == "root")
                {
                    if(h[1] == a)puts("T");
                    else puts("F");
                }
                else
                {
                    cin>>s;
                    int b;cin>>b;
                    int u2 = find(1, b);
                    if(u1 == u2 / 2)puts("T");
                    else puts("F");
                }
            }
            else
            {
                cin>>s>>s;
                int b;cin>>b;
                int u2 = find(1, b);
                if(u1 / 2 == u2)puts("T");
                else puts("F");
            }
        }
        else
        {
            int b;cin>>b;
            cin>>s>>s;
            int u2 = find(1, b);
            if(abs(u1 - u2) == 1 && u1 / 2 == u2 / 2)puts("T");
            else puts("F");
        }
    }
    return 0;
}

L2-013 红色警报

并查集

用的暴力,每次丢一个城市就算一下集合个数

每一次比上一次集合个数多了1个以上就红警,因为把这个城市去掉,这个城市本身是单独集合,大于原来的集合+1就说明去掉的城市所在集合中其他城市连通性变了

#include <bits/stdc++.h>
using namespace std;
const int N = 510;
int p[N];
typedef pair<int, int> PII;
vector<PII> v;
bool lost[N];
int find(int x)
{
    if(p[x] != x)p[x] = find(p[x]);
    return p[x];
}
void join(int a, int b)
{
    a = find(a), b = find(b);
    p[a] = b;
}
int main()
{
    int n, m;cin>>n>>m;
    for(int i = 0; i < n; i ++)p[i] = i;
    while(m --)
    {
        int l, r;cin>>l>>r;
        v.push_back({l, r});
        join(l, r);
    }
    int cnt = 0;
    for(int i = 0; i < n; i ++)if(p[i] == i)cnt ++;
    int k;cin>>k;
    for(int j = 1; j <= k; j ++)
    {
        int a;cin>>a;
        lost[a] = true;
        for(int i = 0; i < n; i ++)p[i] = i;
        for(auto [x, y] : v)
        {
            if(!lost[x] && !lost[y])
                join(x, y);
        }
        int cnt0 = 0;
        for(int i = 0; i < n; i ++)if(p[i] == i)cnt0 ++;
        
        if(cnt0 > cnt + 1)printf("Red Alert: City %d is lost!", a);
        else printf("City %d is lost.", a);
        cout<<endl;
        if(j == n)puts("Game Over.");
        cnt = cnt0;
    }
    return 0;
}

L2-014 列车调度

二分 单调递增 O(nlogn)

对于每个编号,每次编号找比他大的最小编号(贪心),编号替代原先编号,没找到就新建平行铁轨。然后就形成了一个单调递增的数组,每次找最小的就是从前往后找,可使用upper_bound或lower_bound函数序号肯定各不相同,存在相同就用upper_bound

#include <bits/stdc++.h>
using namespace std;
const int N = 1e5 + 10;
int q[N];

int main()
{
    int cnt = 0;
    int n;cin>>n;
    for(int i = 1; i <= n; i ++)
    {
        int x;cin>>x;
        int pos = lower_bound(q, q + cnt, x) - q;
        if(pos == cnt)q[cnt ++] = x;
        else q[pos] = x;
    }
    cout<<cnt;
    return 0;
}

L2-015 互评成绩

记录每人总分、最高分、最低分,总分减去最高最低,排序,输出平均

#include <bits/stdc++.h>
using namespace std;

int main()
{
    int n, m, k;
    cin>>n>>m>>k;
    vector<double> v(n, 0), mx(n, 0), mn(n, 1e9);
    for(int i = 0; i < n; i ++)
        for(int j = 0; j < m; j ++)
        {
            double x;cin>>x;
            v[i] += x;
            mx[i] = max(mx[i], x);
            mn[i] = min(mn[i], x);
        }
    for(int i = 0; i < n; i ++)v[i] -= mn[i] + mx[i];
    sort(v.begin(), v.end(), greater<double>());
    for(int i = k - 1; i >= 0; i --)
    {
        printf("%.3f", v[i] / (m - 2));
        if(i)cout<<' ';
    }
    return 0;
}

L2-016 愿天下有情人都是失散多年的兄妹

小模拟,直接暴力五代往上收集家庭成员然后看是否重复就行,坑点就是

注意:题目保证两个人是同辈,每人只有一个性别,并且血缘关系网中没有乱伦或隔辈成婚的情况。

两个人是同辈,那就是可以是某些人父母辈,那么在统计信息的时候就要统计一下父母的性别

#include <bits/stdc++.h>
using namespace std;

struct node
{
    int sex = -2, fa = -1, ma = -1;
}inf[100010];

int main()
{
    int n;cin>>n;
    for(int i = 0; i < n; i ++)
    {
        int id, sex, fa, ma;
        char c;
        cin>>id>>c>>fa>>ma;
        sex = c == 'M' ? 1 : 0;
        inf[id] = {sex, fa, ma};
        if(~fa)inf[fa].sex = 1;
        if(~ma)inf[ma].sex = 0;
    }
    int m;cin>>m;
    while(m --)
    {
        int a, b;cin>>a>>b;
        if(inf[a].sex == inf[b].sex)puts("Never Mind");
        else
        {
            bool flag = true;
            vector<int> l, r;
            l.push_back(a), r.push_back(b);
            vector<int>mem1 = l, mem2 = r;
            
            for(int k = 0; k < 4; k ++)
            {
                vector<int> ll, rr;
                for(auto i : l)
                {
                    if(inf[i].sex == -2)continue;
                    if(inf[i].fa != -1)ll.push_back(inf[i].fa);
                    if(inf[i].ma != -1)ll.push_back(inf[i].ma);
                }
                for(auto i : r)
                {
                    if(inf[i].sex == -2)continue;
                    if(inf[i].fa != -1)rr.push_back(inf[i].fa);
                    if(inf[i].ma != -1)rr.push_back(inf[i].ma);
                }
                l = ll, r = rr;
                for(auto i : l)mem1.push_back(i);
                for(auto i : r)mem2.push_back(i);
            }
            for(auto i : mem1)
                for(auto j : mem2)
                    if(i == j)flag = false;
            if(flag)puts("Yes");
            else puts("No");
        }
    }
    return 0;
}

L2-017 人以群分

水题

排序,一半(下取整)给内向,一半(上取整)给外向

#include <bits/stdc++.h>
using namespace std;


int main()
{
    int n;cin>>n;
    vector<int> v(n);
    for(int i = 0; i < n; i ++)
        cin>>v[i];
    sort(v.begin(), v.end());
    int mid = n / 2;
    int sum = 0;
    for(int i = 0; i < n; i ++)
    {
        if(i < mid)sum -= v[i];
        else sum += v[i];
    }
    printf("Outgoing #: %d\n", (n + 1) / 2);
    printf("Introverted #: %d\n", n / 2);
    printf("Diff = %d", sum);
    return 0;
}

L2-018 多项式A除以B

小模拟

用map分别存AB的指数和系数,按指数大到小排序,一直除并记录商就行了,余数为A

#include <iostream>
#include <map>
using namespace std;
map<int, double, greater<int>> a, b, s, a1, b1;
int main()
{
    int n;cin>>n;
    while(n --)
    {
        int x;cin>>x;
        cin>>a[x];
    }
    cin>>n;
    while(n --)
    {
        int x;cin>>x;
        cin>>b[x];
    }

    while(a.begin() -> first >= b.begin() -> first)
    {
        int r = a.begin() -> first - b.begin() -> first;
        double c = a.begin() -> second / b.begin() -> second;
        s[r] = c;
        for(auto i : b)
            a[i.first + r] -= c * i.second;
        a.erase(a.begin());
    }

    for(auto i : s)
        if(abs(i.second) >= 0.05)a1[i.first] = i.second;
    for(auto i : a)
        if(abs(i.second) >= 0.05)b1[i.first] = i.second;
    cout<<a1.size();
    if(a1.size() != 0)
        for(auto i : a1)printf(" %d %.1f", i.first, i.second);
    else cout<<" 0 0.0";
    cout<<endl;
    cout<<b1.size();
    if(b1.size() != 0)
        for(auto i : b1)printf(" %d %.1f", i.first, i.second);
    else cout<<" 0 0.0";

    return 0;
}

L2-019 悄悄关注

小模拟

集合存关注,边读边记录点赞总次数和非关注人的点赞次数,最后根据平均值得到悄悄关注的人

#include <bits/stdc++.h>
using namespace std;

int main()
{
    int n;cin>>n;
    set<string> s;
    while(n --)
    {
        string x;cin>>x;
        s.insert(x);
    }
    vector<pair<string, int>>v, tmp;
    int m;cin>>m;
    int sum = 0;
    for(int i = 0; i < m; i ++)
    {
        string a;int b;cin>>a>>b;
        sum += b;
        if(!s.count(a))v.push_back({a, b});
    }
    for(auto i : v)
        if(i.second > sum / m)tmp.push_back(i);
    v = tmp;
    if(v.size() == 0)cout<<"Bing Mei You";
    else
    {
        sort(v.begin(), v.end());
        for(auto [x, y] : v)
            cout<<x<<endl;
    }
    return 0;
}

L2-020 功夫传人

BFS

逆天坑点:祖师爷得道

#include <bits/stdc++.h>
using namespace std;

const int N = 1e5 + 10;
vector<int> g[N];
double va[N];

int main()
{
    int n;
    double z, r;
    cin>>n>>z>>r;
    for(int i = 0; i < n; i ++)
    {
        int k;cin>>k;
        if(k)
            while(k --)
            {
                int x;cin>>x;
                g[i].push_back(x);
            }
        else 
        {
            double x;cin>>x;
            va[i] = x;
        }
    }
    
    double ans = 0;
    if(n == 1)ans = va[0] * z;
    else 
    {
        queue<int>q;
        q.push(0);
        va[0] = z;
        r = 1.0 - r / 100.0;

        while(q.size())
        {
            int t = q.front();
            q.pop();
            for(auto i : g[t])
            {
                ans += va[t] * r * va[i];
                va[i] = va[t] * r;
                q.push(i);
            }
        }
    }
    cout<<(int)ans;
    return 0;
}

L2-021 点赞狂魔

自定义排序

标签出现次数平均值最小 点赞标签种类相同,k越大平均值越小

#include <bits/stdc++.h>
using namespace std;

int main()
{
    int n;cin>>n;
    vector<pair<int, string>>v;
    while(n --)
    {
        string s;cin>>s;
        int k;cin>>k;
        set<int> S;
        for(int i = 0; i < k; i ++)
        {
            int id;cin>>id;
            S.insert(id);
        }
        v.push_back({S.size() * 1000 - k, s});
    }
    sort(v.begin(), v.end());
    
    v.insert(v.begin(), 2,  {0, "-"});
    int m = v.size();
    cout<<v[m - 1].second<<' '<<v[m - 2].second<<' '<<v[m - 3].second;

    return 0;
}

L2-022 重排链表

数据结构 链表

读入的时候不仅记录正向,还记录反向,从两边往中间遍历即可

#include <iostream>
using namespace std;
const int N = 100010;
int ne[N], pre[N], e[N];

int main()
{
    int st, end;
    int n;
    cin>>st>>n;
    while(n --)
    {
        int a, b, c;cin>>a>>b>>c;
        ne[a] = c;
        e[a] = b;
        if(c == -1)end = a;
        else
            pre[c] = a;
    }

    while(1)
    {
        if(st != end) printf("%05d %d %05d\n", end, e[end], st);
        else break;
        end = pre[end];
        if(st != end) printf("%05d %d %05d\n", st, e[st], end);
        else break;
        st = ne[st];
    }
    printf("%05d %d -1", st, e[st]);

    return 0;
}

L2-023 图着色问题

虚张声势题

看似图着色问题,实际只需要存下边,每次记录点颜色,然后去判断所有边上两点颜色是否相同

#include <bits/stdc++.h>
using namespace std;

vector<pair<int, int>> pa;
int color[510];

int main()
{
    int v, e, k;cin>>v>>e>>k;
    while(e --)
    {
        int a, b;cin>>a>>b;
        pa.push_back({a, b});
    }
    int n;cin>>n;
    while(n --)
    {
        for(int i = 1; i <= v; i ++)cin>>color[i];
        bool flag = true;
        set<int> s;
        for(int i = 1; i <= v; i ++)s.insert(color[i]);
        if(k != s.size())flag = false;
        for(auto [x, y] : pa)
            if(color[x] == color[y])
                flag = false;
        if(flag)cout<<"Yes"<<endl;
        else cout<<"No"<<endl;
    }
    return 0;
}

L2-024 部落

并查集 模板题

#include <iostream>
using namespace std;
int p[10010];
int find(int x)
{
    if(p[x] != x)p[x] = find(p[x]);
    return p[x];
}

int main()
{
    int n;cin>>n;
    for(int i = 1; i <= 10000; i ++)p[i] = i;
    int mn = 0;
    while(n --)
    {
        int k, r;cin>>k>>r;
        mn = max(mn, r);
        while(-- k)
        {
            int x;cin>>x;
            mn = max(mn, x);
            r = find(r), x = find(x);
            if(r != x)p[r] = x;
        }
    }
    int jihe = 0;
    for(int i = 1; i <= mn; i ++)
        if(p[i] == i)jihe ++;
    cout<<mn<<' '<<jihe<<endl;
    int q;cin>>q;
    while(q --)
    {
        int a, b;cin>>a>>b;
        a = find(a), b = find(b);
        if(a == b)cout<<'Y'<<endl;
        else cout<<'N'<<endl;
    }
    return 0;
}

L2-025 分而治之

看似并查集,实则不需要

直接存边,每次判断是否存在一条边满足边上两点都没被攻陷即可

#include <bits/stdc++.h>
using namespace std;

typedef pair<int, int> PII;
vector<PII> v;
bool st[10010];
int main()
{
    int n, m;cin>>n>>m;
    while(m --)
    {
        int a, b;cin>>a>>b;
        v.push_back({a, b});
    }
    int q;cin>>q;
    while(q --)
    {
        int num;cin>>num;
        memset(st, 0, sizeof st);
        for(int i = 0; i < num; i ++)
        {
            int x;cin>>x;
            st[x] = true;
        }
        bool flag = true;
        for(auto [x, y] : v)
        {
            if(!st[x] && !st[y])
                flag = false;
        }
        if(flag)cout<<"YES"<<endl;
        else cout<<"NO"<<endl;
    }
    return 0;
}

L2-026 小字辈

简单深搜,

记录辈分及辈分编号最大值

#include <bits/stdc++.h>
using namespace std;

int rk[100010];
vector<int> g[100010];
int mx = 1;
void dfs(int u, int r)
{
    rk[u] = r;
    mx = max(mx, r);
    for(auto i : g[u])
        dfs(i, r + 1);
}
int main()
{
    int n;cin>>n;
    int root;
    for(int i = 1; i <= n; i ++)
    {
        int x;cin>>x;
        if(x == -1)root = i;
        else g[x].push_back(i);
    }
    dfs(root, 1);
    cout<<mx<<endl;
    bool flag = true;
    for(int i = 1; i <= n; i ++)
        if(rk[i] == mx)
        {
            if(!flag)cout<<' ';
            flag = false;
            cout<<i;
        }
    return 0;
}

L2-027 名人堂与代金券

自定义排序

#include <bits/stdc++.h>
using namespace std;

int main()
{
    int n, g, k;
    cin>>n>>g>>k;
    vector<pair<int, string>> v(n + 1);
    int sum = 0;
    for(int i = 1; i <= n; i ++)
    {
        string s;cin>>s;
        int num; cin>>num;
        v[i] = {num, s};
        if(num >= g)sum += 50;
        else if(num >= 60)sum += 20;
    }
    cout<<sum<<endl;
    sort(v.begin() + 1, v.end(), [&](pair<int, string> a, pair<int, string>b){
        if(a.first != b.first)return a.first > b.first;
        return a.second < b.second;
    });
    for(int i = 1; i <= k; i ++)
    {
        auto [x, y] = v[i];
        cout<<i<<' '<<y<<' '<<x<<endl;
        int j = i + 1;
        while(j <= n && v[j].first == x)
        {
            cout<<i<<' '<<v[j].second<<' '<<v[j].first<<endl;
            j ++;
        }
        i = j - 1;
    }
    return 0;
}

L2-028 秀恩爱分得快

小模拟

坑点:直接读数字的话读入-0的时候无法判断性别,得读入字符串然后转化

#include <bits/stdc++.h>
using namespace std;
const int N = 1010;
double g[N][N];
bool sex[N];

int toi(string s){//将字符串转化为正整数 
    int x=0;
    if(s[0]=='-')for(int i=1;i<s.size();++i)x*=10,x+=s[i]-'0';
    else for(int i=0;i<s.size();++i)x*=10,x+=s[i]-'0';
    return x;
}

int main()
{
    ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
    int n, m;
    cin>>n>>m;
    while(m --)
    {
        int k;cin>>k;
        double t = 1.0 / k;
        vector<int> v;
        for(int i = 0; i < k; i ++)
        {
            string s;cin>>s;
            int x = toi(s);
            if(s[0] == '-')sex[x] = true;
            v.push_back(x);
        }
        for(int i = 0; i < v.size(); i ++)
            for(int j = i + 1; j < v.size(); j ++)
            {
                if(sex[v[i]] == sex[v[j]])continue;
                g[v[i]][v[j]] += t, g[v[j]][v[i]] += t;
            }
    }
    
    string s;cin>>s;
    int a = toi(s);
    if(s[0] == '-')sex[a] = true;
    cin>>s;
    int b = toi(s);
    if(s[0] == '-')sex[b] = true;

    double m1 = 0, m2 = 0;
    vector<int> pa, pb;
    for(int i = 0; i < n; i ++)
    {
        if(sex[a] != sex[i] && m1 <= g[i][a])
        {
            if(m1 < g[i][a])pa.clear();
            m1 = g[i][a];
            pa.push_back(i);
        }
        if(sex[b] != sex[i] && m2 <= g[i][b])
        {
            if(m2 < g[i][b])pb.clear();
            m2 = g[i][b];
            pb.push_back(i);
        }
    }

    if(m1 == g[a][b] && m1 == m2)
    {
        if(sex[a])cout<<'-'<<a<<' '<<b;
        else cout<<a<<' '<<'-'<<b;
    }
    else
    {
        for(auto i : pa)
        {
            if(sex[a])cout<<'-'<<a<<' '<<i;
            else cout<<a<<' '<<'-'<<i;
            cout<<endl;
        }
        for(auto i : pb)
        {
            if(sex[b])cout<<'-'<<b<<' '<<i;
            else cout<<b<<' '<<'-'<<i;
            cout<<endl;
        }
    }
    return 0;
}

L2-029 特立独行的幸福

暴力枚举每个数,不断做平方和,过程中得到的数都标记为不特立独行,最后得到1或者出现重复数就跳出循环

#include <bits/stdc++.h>
using namespace std;
map<int, int> mp;
bool st[10010];
bool is(int x)
{
    for(int i = 2; i <= x / i; i ++)
        if(x % i == 0)return false;
    return true;
}
int main()
{
    int l, r;cin>>l>>r;
    for(int i = l; i <= r; i ++)
    {
        vector<int> v;
        int t = i;
        while(t != 1)
        {
            int sum = 0;
            while(t)sum += (t % 10) * (t % 10), t /= 10;
            t = sum;
            if(find(v.begin(), v.end(), t) != v.end())break; //死循环
            v.push_back(t);
            st[t] = true;  //t有依赖
        }
        if(t == 1)mp[i] = v.size();
    }
    for(auto [x, y] : mp)
        if(!st[x])
        {
            if(is(x))cout<<x<<' '<<y * 2<<endl;
            else cout<<x<<' '<<y<<endl;
        }
    if(!mp.size())cout<<"SAD";
    return 0;
}

L2-030 冰岛人

记录一个人的性别和父亲,这里主要判断父族是否相同,存在乱伦情况

#include<bits/stdc++.h>
using namespace std;
struct node
{
    char sex;
    string fa;
};
map<string, node> mp;

bool f(string a, string b)
{
    int i = 1, j = 1;
    string A, B;
    for(A = a; !A.empty(); A = mp[A].fa, i ++)
        for(B = b, j = 1; !B.empty(); B = mp[B].fa, j ++)
        {
            if(i >= 5 && j >= 5)break;
            if(A == B)return false;
        }

    return true;
}


int main()
{
    int n;cin>>n;
    while(n --)
    {
        string a, b;cin>>a>>b;
        if(b.back() == 'n')mp[a] = {'m', b.substr(0, b.size() - 4)};
        else if(b.back() == 'r')mp[a] = {'f', b.substr(0, b.size() - 7)};
        else mp[a].sex = b.back();
    }
    int m;cin>>m;
    while(m --)
    {
        string a, b, c;cin>>a>>c>>b>>c;
        if(!mp.count(a) || !mp.count(b))puts("NA");
        else if(mp[a].sex == mp[b].sex)puts("Whatever");
        else cout<<(f(a, b) ? "Yes" : "No")<<endl;
    }
    return 0;
}

L2-031 深入虎穴

BFS 模板

#include <bits/stdc++.h>
using namespace std;

int d[100010];
vector<int> g[100010];
bool st[100010];
int ans = 0, id;
void bfs(int u)
{
    queue<int>q;
    q.push(u);
    while(q.size())
    {
        int t = q.front();
        q.pop();

        for(auto i : g[t])
        {
            d[i] = d[t] + 1;
            if(ans < d[i])
            {
                ans = d[i];
                id = i;
            }
            q.push(i);
        }
    }
}

int main()
{
    int n;cin>>n;
    for(int i = 1; i <= n; i ++)
    {
        int k;cin>>k;
        while(k --)
        {
            int x;cin>>x;
            g[i].push_back(x);
            st[x] = true;
        }
    }
    
    int root = 1;
    while(st[root])root ++;
    id = root;
    bfs(root);
    cout<<id;
    return 0;
}

L2-032 彩虹瓶

模拟栈

每次从前往后依次处理,如果栈里面有需要的编号就出栈,没有就按顺序找,匹配就找下一个编号,不匹配就放栈里

#include <bits/stdc++.h>

using namespace std;

int main()
{
    int n, m, k;
    cin>>n>>m>>k;
    while(k --)
    {
        stack<int> s;
        bool flag = true;
        vector<int> v(n + 1);
        for(int i = 1; i <= n; i ++)cin>>v[i];
        int num = 1;
        for(int i = 1; i <= n; i ++)
        {
            if(v[i] == num)num ++;
            else
            {
                while(s.size() && s.top() == num)
                {
                    s.pop();
                    num ++;
                }
                s.push(v[i]);
                if(s.size() > m)flag = false;
            }
        }
        while(s.size() && s.top() == num)
        {
            s.pop();
            num ++;
        }
        if(s.size())flag = false;
        if(flag)puts("YES");
        else puts("NO");
    }
    return 0;
}

L2-033 简单计算器

模拟栈

#include <bits/stdc++.h>
using namespace std;

int main()
{
    stack<int>s;
    stack<char>op;
    int n;cin>>n;
    for(int i = 1; i <= n; i ++)
    {
        int x;cin>>x;
        s.push(x);
    }
    for(int i = 1; i < n; i ++)
    {
        char c;cin>>c;
        op.push(c);
    }
    while(op.size())
    {
        int a, b;
        a = s.top();
        s.pop();
        b = s.top();
        s.pop();
        char c = op.top();op.pop();
        int num;
        if(c == '+')num = b + a;
        if(c == '-')num = b - a;
        if(c == '*')num = b * a;
        if(c == '/')
        {
            if(a == 0)
            {
                printf("ERROR: %d/0", b);
                return 0;
            }
            num = b / a;
        }
        s.push(num);
    }
    cout<<s.top();
    return 0;
}

L2-034 口罩发放

中模拟

需要记下姓名、编号、状况、时间、申请顺序,排序按照时间和申请顺序排列,

坑点:判断是否申请超过p天不是判断p*24*60分钟而是直接判断日期天

#include <bits/stdc++.h>
using namespace std;
struct node
{
    string name, id;
    int con;
    int ti;
    int sx;
    bool operator < (const node & W)
    {
        if(ti != W.ti)return ti < W.ti;
        return sx < W.sx;
    }
};

bool check(string id) // 检查身份证是否合法
{
    int len = id.size();
    if (len != 18) return false;
    else
    {
        for (int i = 0; i < len; i++)
            if (id[i] < '0' || id[i] > '9')
                return false;
    }
    return true;
}

map<string, int>last;
vector<string>v;
map<string, string>mp;
int main()
{
    int d, p;cin>>d>>p;
    for(int day = 1; day <= d; day ++) // 遍历每一天
    {
        int n, k;cin>>n>>k;
        vector<node>peo;
        for(int j = 0; j < n; j ++)
        {
            string a, b;cin>>a>>b;
            int con, h, m;char c;
            cin>>con>>h>>c>>m;
            if(!check(b))continue;

            mp[b] = a; // 正确id对应名字
            if(con == 1 && find(v.begin(), v.end(), b) == v.end())v.push_back(b); // 收集患病数据
            peo.push_back({a, b, con, h * 60 + m, j});
        }
        sort(peo.begin(), peo.end()); //按时间和申请顺序排序
        for(int i = 0; i < peo.size(); i ++)
        {
            string a = peo[i].name, b = peo[i].id;
            int con = peo[i].con, t = peo[i].ti;

            if(k == 0)continue; //当天名额发完
            if(last.count(b) && last[b] + p >= day)continue; //申请过并且申请时间太短
            last[b] = day;//更新申请时间
            k --;
            cout<<a<<' '<<b<<endl;//发放口罩
        }
    }
    for(auto a : v)
        cout<<mp[a]<<' '<<a<<endl;

    return 0;
}

L2-035 完全二叉树的层序遍历

这个比较新奇,对输入dfs即可,深读

#include <iostream>
using namespace std;

int tr[100];
int n;
void create(int u)
{
    if(u > n)return ;
    create(u << 1);
    create(u << 1 | 1);
    cin>>tr[u];
}

int main()
{
    cin>>n;
    create(1);
    for(int i = 1; i <= n; i ++)
    {
        if(i != 1)cout<<' ';
        cout<<tr[i];
    }
    return 0;
}

L2-036 网红点打卡攻略

最小生成树?prim?nonono

题目已经把方案给了,直接算就行了

#include <bits/stdc++.h>
using namespace std;

const int N = 210;
int g[N][N];

int main()
{
    memset(g, 0x3f, sizeof g);
    int n, m;cin>>n>>m;
    while(m --)
    {
        int a, b, c;cin>>a>>b>>c;
        g[a][b] = g[b][a] = min(g[a][b], c);
    }
    int k;cin>>k;
    int cnt = 0;
    int id, cost = 1e9;
    for(int i = 1; i <= k; i ++)
    {
        bool flag = true;
        int num;cin>>num;
        vector<int> v;
        v.push_back(0);
        int mon = 0;
        bool st[N] = {0};
        for(int j = 0; j < num; j ++)
        {
            int x;cin>>x;
            if(g[v[j]][x] == 0x3f3f3f3f)flag = false;
            st[x] = true;
            v.push_back(x);
            mon += g[v[j]][x];
        }
        if(g[v[v.size() - 1]][0] == 0x3f3f3f3f)flag = false;
        mon += g[v[v.size() - 1]][0];
        if(num != n)continue;
        for(int i = 1; i <= n; i ++)if(!st[i])flag = false;
        if(!flag)continue;
        cnt ++;
        if(mon < cost)
        {
            cost = mon;
            id = i;
        }
    }
    cout<<cnt<<endl<<id<<' '<<cost;
    return 0;
}

L2-037 包装机

模拟栈

#include <bits/stdc++.h>
using namespace std;

int n, m, mx;
stack<char> stk[110];
int main()
{
    cin>>n>>m>>mx;
    for(int i = 1; i <= n; i ++)
    {
        string s;cin>>s;
        for(int j = s.size() - 1; j >= 0; j --)
            stk[i].push(s[j]);
    }
    int op;
    stack<char> s;
    while(cin >> op, op != -1)
    {
        if(op > 0)
        {
            if(!stk[op].size())continue;
            if(s.size() >= mx && s.size())// 筐满
            {
                cout<<s.top();
                s.pop();
            }
            s.push(stk[op].top());
            stk[op].pop();
        }
        else
        {
            if(s.size()) // 筐不空
            {
                cout<<s.top();
                s.pop();
            }
        }
    }
    return 0;
}

L2-038 病毒溯源

找到根,深搜找最长路

#include <bits/stdc++.h>
using namespace std;

vector<int> g[10010];
int d[10010];
int ans = 0, ed;
int pre[10010];
int root;
bool st[10010];

void dfs(int u)
{
    for(int i : g[u])
    {
        d[i] = d[u] + 1;
        pre[i] = u;
        dfs(i);
        if(d[i] > ans)
        {
            ans = d[i];
            ed = i;
        }
    }
}

int main()
{
    int n;cin>>n;
    for(int i = 0; i < n; i ++)
    {
        int k;cin>>k;
        while(k --)
        {
            int x;cin>>x;
            g[i].push_back(x);
            st[x] = true;
        }
        sort(g[i].begin(), g[i].end());
    }
    root = 0;
    while(st[root])root ++;
    dfs(root);
    cout<<ans + 1<<endl;
    vector<int> v;
    while(ed != root)
    {
        v.push_back(ed);
        ed = pre[ed];
    }
    cout<<root;
    for(int i = v.size() - 1; i >= 0; i --)
        cout<<' '<<v[i];
    return 0;
}

L2-039 清点代码库

相同输入输出视为一个模块,那么我们用map对每一行做映射,记录次数即可

#include <bits/stdc++.h>
using namespace std;

bool cmp(pair<vector<int>, int> a, pair<vector<int>, int> b)
{
    auto [x, y] = a;
    auto [xx, yy] = b;
    if(y != yy)return y > yy;
    for(int i = 0; i < x.size(); i ++)
    {
        if(x[i] != xx[i])
            return x[i] < xx[i];
    }
}

map<vector<int>, int> cnt;

int main()
{
    int n, m;
    cin>>n>>m;
    for(int i = 0; i < n; i ++)
    {
        vector<int> v(m);
        for(int j = 0; j < m; j ++)
            cin>>v[j];
        cnt[v] ++;
    }
    vector<pair<vector<int>, int>> ve;
    for(auto i : cnt)ve.push_back(i);
    sort(ve.begin(), ve.end(), cmp);
    cout<<ve.size()<<endl;
    for(auto [x, y] : ve)
    {
        cout<<y;
        for(int i = 0; i < x.size(); i ++)
            cout<<" "<<x[i];
        cout<<endl;
    }
    return 0;
}

L2-040 哲哲打游戏

小模拟

#include <bits/stdc++.h>
using namespace std;
const int N = 1e5 + 10;
vector<int> g[N];
int d[N];
int main()
{
    int n, m;cin>>n>>m;
    for(int i = 1; i <= n; i ++)
    {
        int k;cin>>k;
        while(k --)
        {
            int x;cin>>x;
            g[i].push_back(x);
        }
    }
    int now = 1;
    while(m --)
    {
        int op;cin>>op;
        int x;cin>>x;
        if(!op)
            now = g[now][x - 1];
        else if(op == 1)
        {
            cout<<now<<endl;
            d[x] = now;
        }
        else
            now = d[x];
    }
    cout<<now;
    return 0;
}

L2-041 插松枝

中模拟

盒子是一个栈,推送器用队列表示

以栈和队列中都没东西作为循环结束

#include <bits/stdc++.h>
using namespace std;
stack<int> s; //盒子
queue<int> q;
vector<int>ans;
int n, m, k;
bool check()
{
    if(!ans.size())return false;
    if(s.size() == m && s.top() > ans.back() && q.size() && q.front() > ans.back())return true;//1 盒子满 推送器没法用
    if(s.size() && s.top() > ans.back() && !q.size())return true; //2 盒子有但不符合,推送器空
    if(ans.size() == k)return true; //3 松枝干满
    return false;
}
int main()
{
    cin>>n>>m>>k;
    for(int i = 0; i < n; i ++)
    {
        int x;cin>>x;
        q.push(x);
    }
    
    while(s.size() || q.size())
    {
        if(check())
        {
            for(int i = 0; i < ans.size(); i ++)
            {
                if(i)cout<<' ';
                cout<<ans[i];
            }
            cout<<endl;
            ans.clear();
        }
        if(s.size() && (!ans.size() || s.top() <= ans.back())) //用盒子
        {
            ans.push_back(s.top());
            s.pop();
        }
        else if(q.size() && (!ans.size() || q.front() <= ans.back())) // 用推送
        {
            ans.push_back(q.front());
            q.pop();
        }
        else if(q.size() && s.size() < m) //放盒子
        {
            s.push(q.front());
            q.pop();
        }
    }
    if(ans.size())
        for(int i = 0; i < ans.size(); i ++)
        {
            if(i)cout<<' ';
            cout<<ans[i];
        }
    return 0;
}

L2-042 老板的作息表

小模拟

对时间区间排个序,然后按时间处理

#include <bits/stdc++.h>
using namespace std;
typedef pair<int, int> PII;
vector<PII> v;

int main()
{
    int n;cin>>n;
    for(int i = 0; i < n; i ++)
    {
        int a, b, c;
        char x;
        cin>>a>>x>>b>>x>>c;
        int t1, t2;
        t1 = a * 3600 + b * 60 + c;
        cin>>x;
        cin>>a>>x>>b>>x>>c;
        t2 = a * 3600 + b * 60 + c;
        v.push_back({t1, t2});
    }
    sort(v.begin(), v.end());
    int last = 0;
    for(int i = 0; i < n; i ++)
    {
        auto [x, y] = v[i];
        if(x != last)
        {
            int a1 = last / 3600, a2 = last / 60 % 60, a3 = last % 60;
            int b1 = x / 3600, b2 = x / 60 % 60, b3 = x % 60;
            printf("%02d:%02d:%02d - %02d:%02d:%02d\n", a1, a2, a3, b1, b2, b3);
        }
        last = y;
    }
    if(last != 24 * 3600 - 1)
    {
        int a1 = last / 3600, a2 = last / 60 % 60, a3 = last % 60;
        printf("%02d:%02d:%02d - %02d:%02d:%02d\n", a1, a2, a3, 23, 59, 59);
    }
    return 0;
}

L2-043 龙龙送外卖

dfs

首先存下每个结点的父结点、子结点,用子结点计算深度,即与外卖站的距离,

然后对于每个新增结点,往上找父亲结点,将路过的没遍历过的点都标记,直到遇到标记过的点,距离加上往上找的次数*2,相当于一个来回,最后输出减去回去的长度即可

即将经过的站作为新树树干,新增一个结点要连到这个树干上

#include <bits/stdc++.h>
using namespace std;
const int N = 1e5 + 10;
vector<int> son[N];
int fa[N];
int depth[N];

void dfs(int u, int d)
{
    depth[u] = d;
    for(auto i : son[u])
        dfs(i, d + 1);
}
int ans;
bool st[N];
void dfs2(int u)
{
    if(st[u])return;
    st[u] = true;
    ans += 2;
    dfs2(fa[u]);
}

int main()
{
    int n, m;cin>>n>>m;
    int root;
    for(int i = 1; i <= n; i ++)
    {
        int x;cin>>x;
        if(x == -1)root = i;
        else son[x].push_back(i), fa[i] = x;
    }
    dfs(root, 0);
    int mx = 0; // 回来的长度
    st[root] = true;

    while(m --)
    {
        int x;cin>>x;
        mx = max(mx, depth[x]);
        if(st[x])cout<<ans - mx<<endl;
        else 
        {
            dfs2(x);
            cout<<ans-mx<<endl;
        }
    }
    return 0;
}

L2-044 大众情人

floyd

距离什么的有点混,g[a][b]是a眼中b的距离,也就是对于b来说的,求对b来说最大的异性a的距离就等价于异性缘

#include <bits/stdc++.h>
using namespace std;

const int N = 510;
int g[N][N];// i眼中的j
char sex[N];

int main()
{
    int n;cin>>n;
    memset(g, 0x3f, sizeof g);
    for(int i = 1; i <= n; i ++)
    {
        cin>>sex[i];
        int k;cin>>k;
        while(k --)
        {
            int a, b;char c;
            cin>>a>>c>>b;
            g[i][a] = b;
        }
    }

    for(int k = 1; k <= n; k ++)
        for(int i = 1; i <= n; i ++)
            for(int j = 1; j <= n; j ++)
                g[i][j] = min(g[i][j], g[i][k] + g[k][j]);
        
    vector<int> v1, v2;
    int m1 = 0x3f3f3f3f, m2 = m1;
    for(int i = 1; i <= n; i ++)
    {
        int tmp = -1;
        for(int j = 1; j <= n; j ++)
            if(sex[i] != sex[j])//如果有人不认识异性也算在最大距离里
                tmp = max(tmp, g[j][i]);//求i的最小异性缘,最大距离
        if(~tmp)
        {
            if(sex[i] == 'F')
            {
                if(tmp < m1)
                {
                    v1 = {i};
                    m1 = tmp;
                }
                else if(tmp == m1)v1.push_back(i);
            }
            else
            {
                if(tmp < m2)
                {
                    v2 = {i};
                    m2 = tmp;
                }
                else if(tmp == m2)v2.push_back(i);
            }
        }
    }
    for(int i = 0; i < v1.size(); i ++)
    {
        if(i)cout<<' ';
        cout<<v1[i];
    }
    cout<<endl;
    for(int i = 0; i < v2.size(); i ++)
    {
        if(i)cout<<' ';
        cout<<v2[i];
    }
    return 0;
}

L2-045 堆宝塔

模拟栈

#include <bits/stdc++.h>
using namespace std;

int main()
{
    int n;cin>>n;
    queue<int> q;
    while(n --)
    {
        int x;cin>>x;
        q.push(x);
    }
    stack<int> a, b;

    int mx = 0, cnt = 0;
    while(q.size())
    {
        auto t = q.front();
        q.pop();
        if(a.empty() || a.top() > t)
            a.push(t);
        else
        {
            if(b.empty() || b.top() < t)
                b.push(t);
            else
            {
                cnt ++;
                mx = max(mx, (int)a.size());
                while(a.size())a.pop();
                while(b.size() && b.top() > t)
                {
                    a.push(b.top());
                    b.pop();
                }
                a.push(t);
            }
        }
    }
    if(a.size())cnt ++, mx = max(mx, (int)a.size());
    if(b.size())cnt ++, mx = max(mx, (int)b.size());
    cout<<cnt<<' '<<mx;
    return 0;
}

L2-046 天梯赛的赛场安排

小模拟

用优先队列暴力模拟即可

#include <bits/stdc++.h>
using namespace std;
typedef pair<int, string> PIS;
int main()
{
    int n, c;
    cin>>n>>c;
    vector<string> v;
    map<string, int> mp;
    priority_queue<PIS, vector<PIS>>heap;
    vector<int> kong;
    while(n --)
    {
        string s;int x;cin>>s>>x;
        v.push_back(s);
        heap.push({x, s});
    }
    int cnt = 0;
    while(heap.size())
    {
        auto [x, y] = heap.top();
        heap.pop();
        if(x >= c)
        {
            cnt ++;
            mp[y] ++;
            x -= c;
            if(x)heap.push({x, y});
        }
        else
        {
            mp[y] ++;
            int id = -1;
            for(int i = 0; i < kong.size(); i ++)
                if(kong[i] >= x)
                {
                    id = i;
                    kong[i] -= x;
                    break;
                }
            if(~id)continue;
            kong.push_back(c - x);
            cnt ++;
        }
    }
    for(auto i : v)
        cout<<i<<' '<<mp[i]<<endl;
    cout<<cnt;
    return 0;
}

L2-047 锦标赛

新增一层,将每场比赛的结果按顺序往下存下来,然后dfs暴搜

#include <iostream>
using namespace std;

int k;
int w[(1 << 19) + 10];
bool dfs(int u, int depth, int val)
{
    if(depth == k)
    {
        if(w[u])return false;
        if(u & 1 == 0) // 偶数
        {
            w[u] = val;
            return true;
        }
        else // 奇数
        {
            if(w[u - 1] > val)return false;
            w[u] = val;
            return true;
        }
    }
    
    if(val >= w[u] && dfs(u * 2, depth + 1, val))
    {
        w[u] = val;
        return true;
    }
    if(val >= w[u] && dfs(u * 2 + 1, depth + 1, val))
    {
        w[u] = val;
        return true;
    }
    return false;
}

int main()
{
    cin>>k;
    for(int i = 1; i <= k; i ++)
    {
        int l = 1 << (k - i), r = l * 2 - 1;
        for(int j = l; j <= r; j ++)
        {
            int x;cin>>x;
            if(!dfs(j, k - i, x))
            {
                cout<<"No Solution";
                return 0;
            }
        }
    }
    int x;cin>>x;
    if(!dfs(1, 0, x))
    {
        cout<<"No Solution";
        return 0;
    }
    for(int i = 1 << k; i < 1 << k + 1; i ++)
        cout<<w[i]<<' ';
    return 0;
}

L2-048 寻宝图

flood fill 模板题

#include <bits/stdc++.h>
using namespace std;
int dx[] = {0, 1, 0, -1, 0}, dy[] = {-1, 0, 1, 0, 0};
int main()
{
    int n, m;cin>>n>>m;
    vector<string> g(n);
    for(int i = 0; i < n; i ++)cin>>g[i];
    int cnt = 0, val = 0;
    for(int i = 0; i < n; i ++)
        for(int j = 0; j < m; j ++)
            if(g[i][j] != '0')
            {
                cnt ++;
                bool flag = false;
                queue<pair<int, int>> q;
                q.push({i, j});
                while(q.size())
                {
                    auto [x, y] = q.front();
                    q.pop();
                    for(int k = 0; k < 5; k ++)
                    {
                        int a = x + dx[k], b = y + dy[k];
                        if(a < 0 || a >= n || b < 0 || b >= m)continue;
                        if(g[a][b] == '0')continue;
                        if(g[a][b] > '1')flag = true;
                        q.push({a, b});
                        g[a][b] = '0';
                    }
                }
                if(flag)val ++;
            }
    cout<<cnt<<' '<<val;
    return 0;
}

L2-049 鱼与熊掌

物品对人连边 + 二分搜索

#include <bits/stdc++.h>
using namespace std;

vector<int> g[100010];

int main()
{
    int n, m;cin>>n>>m;
    for(int i = 1; i <= n; i ++)
    {
        int k;cin>>k;
        while(k --)
        {
            int x;cin>>x;
            g[x].push_back(i);
        }
    }

    int q;cin>>q;
    while(q --)
    {
        int cnt = 0;
        int a, b;cin>>a>>b;
        for(auto i : g[a])
        {
            int pos = lower_bound(g[b].begin(), g[b].end(), i) - g[b].begin();
            if(pos == g[b].size())continue;
            if(g[b][pos] == i)cnt ++;
            // cout<<i<<' '<<g[b][pos]<<endl;
        }
        cout<<cnt<<endl;
    }
}

L2-050 懂蛇语

map 单词首字母的组合映射string数组,然后一个一个查

#include <bits/stdc++.h>
using namespace std;

map<string, vector<string>>mp;

int main()
{
    int n; cin>>n;
    getchar();
    while(n --)
    {
        string str;
        getline(cin,str);
        stringstream ss(str);
        string s, a;
        while(ss>>a) s+=a[0];
        mp[s].push_back(str);
    }

    int q;cin>>q;
    getchar();
    while(q --)
    {
        string s;
        getline(cin, s);
        stringstream ss(s);
        string name, a;

        while(ss>>a) name+=a[0];
        // cout<<s<<" ?? "<<name<<endl;
        if(mp.count(name))
        {
            vector<string> v = mp[name];
            sort(v.begin(), v.end());
            cout<<v[0];
            for(int i = 1; i < v.size(); i ++)
                cout<<'|'<<v[i];
            cout<<endl;
        }
        else
            cout<<s<<endl;
    }
    return 0;
}

L2-051 满树的遍历

找到根,深搜判断是否非叶结点度相同,深搜输出前序遍历结果

#include <bits/stdc++.h>
using namespace std;
vector<int> g[100010];

bool flag = true;
int ans = -1;
void dfs(int u)
{
    if(g[u].empty())return ;
    if(ans != -1 && ans != g[u].size())flag = false;
    ans = max(ans, (int)g[u].size());
    for(auto i : g[u])
        dfs(i);
}

void dfs2(int u)
{
    for(auto i : g[u])
    {
        cout<<' '<<i;
        dfs2(i);
    }
}

int main()
{
    int n;cin>>n;
    int root;
    for(int i = 1; i <= n; i ++)
    {
        int x;cin>>x;
        if(!x)root = i;
        else g[x].push_back(i);
    }

    dfs(root);
    if(ans == -1)ans = 0;
    cout<<ans<<' '<<(flag ? "yes" : "no")<<endl;
    cout<<root;
    dfs2(root);
    return 0;
}

L2-052 吉利矩阵

暴力深搜,将矩阵填满就check 计算量16 * 2 ^ 8

#include <iostream>
using namespace std;
int g[10][10];
int sum, n;
int ans = 0;
bool check(int x, int y)
{
    int cnt = 0;
    for(int i = 1; i <= x; i ++)
        cnt += g[i][y];
    if(cnt > sum)return false;
    if(x == n && cnt != sum)return false;
    cnt = 0;
    for(int i = 1; i <= y; i ++)
        cnt += g[x][i];
    if(cnt > sum)return false;
    if(y == n && cnt != sum)return false;
    return true;
}

void dfs(int x, int y)
{
    for(int i = 0; i <= sum; i ++)
    {
        g[x][y] = i;
        if(!check(x, y))continue;
        if(x == n && y == n){ans ++;return ;}
        
        if(y == n)dfs(x + 1, 1);
        else dfs(x, y + 1);
    }
}

int main()
{
    cin>>sum>>n;

    dfs(1, 1);
    cout<<ans<<endl;
    return 0;
}
posted @ 2025-04-14 10:54  与君弈  阅读(100)  评论(0)    收藏  举报