CF339C Xenia and Weights

发布于 2020-08-16  2.6k 次阅读


题面

题意

现在有一个天平,你拥有一些种类的砝码,这些砝码的重量均在 $1 \sim 10$ 间且对于每一种砝码你有无数多个。现在按照两个要求依次放置 $m$ 个砝码,要求如下:

  1. 相邻两次放置操作不能放置相同的砝码
  2. 每次放下砝码后必须保证放下砝码的这个盘的总重量大于另一盘。

其中第一个砝码必须放在左盘,第二个砝码必须放右盘,第三个放左盘,以此类推。

分析

直接 dfs 所有可能的方案,尝试将所有你拥有的砝码放入当前盘,并且按照两个要求进行剪枝。有一些细节,详见代码。

代码

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

bool vis[11];
int record[1005];  //用来记录每轮放置的砝码重量
int m;

//五项参数分别表示当前轮到放到哪盘、左盘重量、右盘重量、已放置砝码数量、上一次放置的砝码重量
bool dfs(int turn, int left, int right, int times, int front) {
    if (times)
        if (turn) {  //如果左右盘的重量并不满足要求2
            if (left <= right)
                return false;
        } else if (left >= right)
            return false;
    if (times == m) {  //如果已放置m个砝码
        puts("YES");
        for (int i = 0; i < times; i++)
            printf("%d ", record[i]);
        puts("");
        return true;
    }
    bool check = false;
    for (int i = 1; i <= 10; i++)
        if (vis[i] && i != front) {  //尝试所有可能放置的砝码,放入当前盘
            record[times] = i;
            if (!turn)
                check |= dfs(!turn, left + i, right, times + 1, i);
            else
                check |= dfs(!turn, left, right + i, times + 1, i);
            if (check)  //一旦任意一种情况满足条件,则直接return
                return true;
        }
    return check;
}

int main() {
    int t;
    scanf("%d", &t);
    for (int i = 10; i; i--) {  //拆分t
        vis[i] = t % 10;
        t /= 10;
    }
    scanf("%d", &m);
    if (!dfs(0, 0, 0, 0, -1))
        puts("NO");
    return 0;
}

我缓慢吐出一串啊吧啊吧并不再想说话