重庆交通大学2022年校赛前第4次练习赛题解(ABCEF)

Problem.A 花圃喷灌

        本题灵感来源于2017年陕西省中考数学的几何压轴题,在算法题中来说这并不算是真正意义上的计算几何题,不过这题的数字被出题人弄得有点难算,但使用的几何定理都是初中数学的,比如垂径定理之类的,而最后的结果其实只需要一句输出,上过程(这题就不放代码了):

 

 Problem.B 火车进出站

        本题其实是数据结构的一个应用,就是求合法的出栈序列,当然也同时致敬一下铁路重庆站,字典序输出合法出栈序列,dfs没话说

vector<int> nums; //存储序列
stack<int> stk; //栈
int n, u, cnt;

void dfs()
{
    if (nums.size() == n && cnt < 20)
    {
        for (auto it : nums)
            cout << it << ' ';
        cout << endl;
        cnt++;
        return;
    }
    if (stk.size())
    {
        nums.push_back(stk.top());
        stk.pop();
        dfs();
        stk.push(nums.back());
        nums.pop_back();
    }
    if (u <= n)
    {
        stk.push(u);
        u++;
        dfs();
        stk.pop();
        u--;
    }
}

void solve()
{
    cin >> n;
    u = 1, cnt = 0;
    dfs();
}

Problem.C 后宫风云

        可以算是本场最难的题目,首先得根据一个题目背景跟图完全没关系的描述中想到二分图,染色法判断二分图是板子了,dfs和bfs都行,而这时又加了层二分,每个人看作一个点,每两个人的怨气值就是连接这两个点的无向边的权值,二分最大的怨气值,染色法判断能否形成二分图,最终找到能使二分图成立的最大怨气值,就是本题的思路,图论题的难点就是要能够发现这是考图论,其次就是建出图来,而图论题的大码量其实很多是板子

const int N = 20010, M = 200010;
int n, m;
int h[N], e[M], w[M], ne[M], idx;
int cor[N];

void add(int p, int x, int c)
{
    e[idx] = x;
    w[idx] = c;
    ne[idx] = h[p];
    h[p] = idx++;
}
//bfs判断二分图,也可用dfs,1,2分别代表两种颜色
bool bfs(int u, int mid)
{
    queue<int> que;
    cor[u] = 1;
    que.push(u);
    while (que.size())
    {
        int t = que.front();
        que.pop();
        for (int i = h[t];i != -1; i = ne[i])
        {
            int j = e[i];
            if (w[i] > mid)
            {
                if (!cor[j])
                {
                    cor[j] = 3 - cor[t];
                    que.push(j);
                }
                else if (cor[j] == cor[t]) return false;
            }
        }
    }
    return true;
}
//是否能够形成二分图
bool check(int mid)
{
    memset(cor, 0, sizeof(cor));
    for (int i = 1; i <= n; i++)
    {
        if (!cor[i] && !bfs(i, mid)) 
            return false;
    }
    return true;
}

void solve()
{
    memset(h, -1, sizeof(h));
    cin >> n >> m;
    int a, b, c;
    int l = 0, r = 0;
    while (m--)
    {
        cin >> a >> b >> c;
        add(a, b, c);
        add(b, a, c);
        r = max(r, c);
    }
    while (l < r)
    {
        int mid = l + r >> 1;
        if (check(mid)) r = mid;
        else l = mid + 1;
    }
    cout << l << endl;
}

Problem.E 骰子

        判断是否同构,就根据两个骰子每个数字对面的数字是不是相同的来判定,由性质可以知道,三行数字中第一行第一个非0数字的对面一定是第三行第一个非0数字,第二行第一个非0数字一定和第二行第三的非0数字相对,而另外两个面就需要枚举一遍了,这题一定要理清思维,思路清晰了就问题不大了

const int N = 5;
int a[N][N], b[N][N];
int s1[10], s2[10];

void opp(int x[][5], int p[])
{
    int temp = 0;
    for (int j = 1; j <= 4; j++)
    {
        if (x[1][j]) temp = x[1][j];
    }
    for (int j = 1; j <= 4; j++)
    {
        if (x[3][j])
        {
            p[temp] = x[3][j];
            p[x[3][j]] = temp;
            break;
        }
    }
    p[x[2][1]] = x[2][3];
    p[x[2][3]] = x[2][1];
    p[x[2][2]] = 7;
    for (int i = 1; i <= 3; i++)
    {
        for (int j = 1; j <= 4; j++)
        {
            if (x[i][j] != 0 && p[x[i][j]] == 0)
            {
                p[x[i][j]] = x[2][2];
                p[x[2][2]] = x[i][j];
                break;
            }
        }
    }
}

void solve()
{
    for (int i = 1; i <= 3; i++)
        for (int j = 1; j <= 4; j++)
            cin >> a[i][j];

    for (int i = 1; i <= 3; i++)
        for (int j = 1; j <= 4; j++)
            cin >> b[i][j];

    opp(a, s1);
    opp(b, s2);
    for (int i = 1;i <= 6; i++)
    {
        if (s1[i] != s2[i])
        {
            cout << "NO" << endl;
            return;
        }
    }
    cout << "YES" << endl;
}

Problem.F Steve的打怪之路

        这题也是比较难的,主要是题干信息比较多,读明白了就是一个二维费用的背包问题

        令dp[i][j][k]表示从前i只怪物里选,使用的体力值不超过j,损失的生命值不超过k的最大打怪数量,打第i只怪物需要消耗的体力为v[i],需要损失的生命为w[i],则可有以下划分

 

则状态转移方程为

dp[i][j][k]=max(dp[i-1][j][k],dp[i-1][j-v[i]][k-w[i]])

这是01背包问题的二维费用问题,那么滚动数组还能够优化掉第一维,值得注意的是,这题中Steve的生命值不能到0,因此能够打败的最大怪物数量应该是dp[s][n][m-1],而要求此时损失的生命值们只需要第三维层层回退就能找到。

void solve()
{
    cin >> s >> n >> m;
    for (int i = 1; i <= s; i++)
    {
        cin >> w[i] >> v[i];
    }

    for (int i = 1; i <= s; i++)
        for (int j = n; j >= w[i]; j--)
            for (int k = m - 1; k >= v[i]; k--)
                dp[j][k] = max(dp[j][k], dp[j - w[i]][k - v[i]] + 1);

    cout << dp[n][m - 1] << ' ';
    int k = m - 1;
    while (k && dp[n][k - 1] == dp[n][m - 1]) k--;
    cout << k << endl;
}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值