副本是游戏里的一个特色玩法,主要为玩家带来装备、道具、游戏资源的产出,满足玩家的游戏进程。
在 MMORPG《最终幻想14》里,有一个攻略人数最大达到 56 人的副本“巴尔德西昂兵武塔”,因为有在副本里死亡不能复活、机制比较整蛊等特点,一度被玩家视作洪水猛兽。
在副本的开始,我们会遇到第一个难关:攻略的玩家要分为两组,同时讨伐副本 BOSS “欧文”和“亚特”。
已知以下信息:
- 玩家会组成 6 支队伍进入副本,其中第 i 队有 Vi 位玩家(i=1,⋯,6)。
- 每支队伍可能会有一些特殊角色:MT(主坦克)、工兵(负责探测陷阱)和指挥(负责指挥玩家)。
我们的任务是合理安排玩家的分组,以最大程度增加副本通过概率。分组的原则如下:
- 要将所有队伍分成 2 组,每支队伍必须且仅属于其中一组;
- 每组必须有至少一个 MT(主坦克)。
如果满足上述原则的分组方案不唯一,则按照下列规则确定唯一解:
- 优先选择每组有至少一个指挥和至少一个工兵的方案;
- 如果规则 1 无法满足,则优先选择每组至少有一个指挥的方案;
- 如果所有方案都不满足规则 2,或经过前 2 个规则筛选后,分组方案仍不唯一,则选择两边人数尽可能接近(即两边人数差尽可能小)的方案;
- 如果满足规则 3 的方案还不唯一,选择讨伐“欧文”的人数大于等于讨伐“亚特”的人数的方案;
- 如果满足规则 4 的方案还不唯一,选择讨伐“欧文”的队伍编号方案中最小的一个。
注:一个队伍编号方案 A={a1<⋯<am} 比 B={b1<⋯<bn} 小,当且仅当存在 1≤k≤min(m,n) 使得 ai=bi 对所有 0<i<k 成立,且 ak<bk。
本题就请你给出满足所有分组原则的分配方案。
感谢 王宪泉 同学对规则 4 的指正,于 2022-08-04 修改
输入格式:
输入第一行给出 6 支队伍的玩家数量,即 6 个非负整数 Vi (0≤Vi≤8,1≤i≤6)。队伍人数为 0 时表示队伍不存在。
随后 6 行,按队伍编号顺序,每行给出一支队伍的特殊角色,格式为 ABC
,其中 A
对应 MT,B
对应工兵,C
对应指挥。三种角色对应取值 0 或 1,0 表示没有该角色,1 表示有。
注:由于可能存在一人兼任多个特殊角色的情况,所以一支队伍中的特殊角色数量有可能大于该队伍的玩家数量。
输出格式:
输出分两行,第一行输出讨伐“欧文”的队伍编号,第二行输出讨伐“亚特”的队伍编号。同一行中的编号按升序输出,以 1 个空格分隔,行首尾不得有多余空格。
如果不存在合法的方案,输出GG
。
输入样例1:
6 8 7 5 3 0
010
101
110
001
111
000
输出样例1:
2 3
1 4 5
输入样例2:
6 8 7 5 3 0
010
101
010
001
011
000
输出样例2:
GG
题意: 根据题目中给出的各种规则,将若干队伍分为两组,若存在方案输出分组方案,否则输出GG。
分析: 这道题目是一道比较麻烦的模拟题,可以先处理下每个队伍是否有MT、工兵和指挥,然后二进制枚举0~1<<6,对于枚举出来的一个数字就代表一种分组方案,这里我假设为1的位是讨伐欧文的队伍,为0的位是讨伐亚特的队伍,首先先找出来两组都包含MT的分组,如果不存在那么说明无解,如果分组唯一那就直接输出,如果分组不唯一就再遍历找出两组均有指挥和工兵的分组方案,如果不存在的话就只考虑指挥,之后就根据题目中的描述模拟就行,要严格按照题目中说的来,另外题面中规则4后来进行了修改,应该是讨伐“欧文”的人数大于等于讨伐“亚特”的人数而不是之前说的的大于!
具体代码如下:
#include <bits/stdc++.h>
#define inf 0x3f3f3f3f
using namespace std;
int num[10];
bool mt[10];
bool gb[10];
bool zh[10];
void Output(int i);
signed main(){
for(int i = 0; i < 6; i++)
scanf("%d", &num[i]);
for(int i = 0; i < 6; i++){
string s;
cin >> s;
mt[i] = (s[0]=='1');
gb[i] = (s[1]=='1');
zh[i] = (s[2]=='1');
}
vector<int> alls;
for(int i = 0; i < (1<<6); i++){
if(i == 0 || i == (1<<6)-1) continue;
bool mt1 = false, mt2 = false;
for(int j = 0; j < 6; j++){
if(i&(1<<j) && num[j])
mt1 = max(mt1, mt[j]);
else if(!(i&(1<<j)) && num[j])
mt2 = max(mt2, mt[j]);
}
if(mt1 && mt2) alls.push_back(i);
}
if(alls.size() > 1){
vector<int> t1;
for(int i = 0; i < alls.size(); i++){
bool gb1 = false, gb2 = false, zh1 = false, zh2 = false;
for(int j = 0; j < 6; j++){
if(alls[i]&(1<<j) && num[j]){
gb1 = max(gb1, gb[j]);
zh1 = max(zh1, zh[j]);
}
else if(!(alls[i]&(1<<j)) && num[j]){
gb2 = max(gb2, gb[j]);
zh2 = max(zh2, zh[j]);
}
}
if(gb1 && gb2 && zh1 && zh2) t1.push_back(alls[i]);
}
if(t1.size() == 0){
for(int i = 0; i < alls.size(); i++){
bool zh1 = false, zh2 = false;
for(int j = 0; j < 6; j++){
if(alls[i]&(1<<j) && num[j]){
zh1 = max(zh1, zh[j]);
}
else if(!(alls[i]&(1<<j)) && num[j]){
zh2 = max(zh2, zh[j]);
}
}
if(zh1 && zh2) t1.push_back(alls[i]);
}
}
if(t1.size() == 1){
int i = t1[0];
Output(i);
}
else{
vector<int> t2;
if(t1.size() > 1){//多个满足前两规则的
int _min = inf;
for(int i = 0; i < t1.size(); i++){
int n1 = 0, n0 = 0;
for(int j = 0; j < 6; j++){
if((t1[i]&(1<<j)) && num[j]){
n1 += num[j];
}
else if(!(t1[i]&(1<<j)) && num[j]){
n0 += num[j];
}
}
if(n1 == 0 || n0 == 0) continue;
_min = min(_min, abs(n1-n0));
}
for(int i = 0; i < t1.size(); i++){
int n1 = 0, n0 = 0;
for(int j = 0; j < 6; j++){
if((t1[i]&(1<<j)) && num[j]){
n1 += num[j];
}
else if(!(t1[i]&(1<<j)) && num[j]){
n0 += num[j];
}
}
if(n1 == 0 || n0 == 0) continue;
if(abs(n1-n0) == _min) t2.push_back(t1[i]);
}
}
else{//不存在满足第二个规则的,更不存在满足前两个的
int _min = inf;
for(int i = 0; i < alls.size(); i++){
int n1 = 0, n0 = 0;
for(int j = 0; j < 6; j++){
if((alls[i]&(1<<j)) && num[j]){
n1 += num[j];
}
else if(!(alls[i]&(1<<j)) && num[j]){
n0 += num[j];
}
}
if(n1 == 0 || n0 == 0) continue;
_min = min(_min, abs(n1-n0));
}
for(int i = 0; i < alls.size(); i++){
int n1 = 0, n0 = 0;
for(int j = 0; j < 6; j++){
if((alls[i]&(1<<j)) && num[j]){
n1 += num[j];
}
else if(!(alls[i]&(1<<j)) && num[j]){
n0 += num[j];
}
}
if(n1 == 0 || n0 == 0) continue;
if(abs(n1-n0) == _min) t2.push_back(alls[i]);
}
}
if(t2.size() == 1){
int i = t2[0];
Output(i);
}
else{//t2.size()不可能为0
vector<int> t3;
for(int i = 0; i < t2.size(); i++){
int n1 = 0, n0 = 0;
for(int j = 0; j < 6; j++){
if((t2[i]&(1<<j)) && num[j]){
n1 += num[j];
}
else if(!(t2[i]&(1<<j)) && num[j]){
n0 += num[j];
}
}
if(n1 == 0 || n0 == 0) continue;
if(n1 >= n0) t3.push_back(t2[i]);
}
if(t3.size() == 1){
int i = t3[0];
Output(i);
}
else if(t3.size() > 1){
vector<vector<int> > ans;
for(int i = 0; i < t3.size(); i++){
vector<int> temp;
for(int j = 0; j < 6; j++){
if((t3[i]&(1<<j)) && num[j]){
temp.push_back(j+1);
}
}
ans.push_back(temp);
}
sort(ans.begin(), ans.end());
bool vis[10] = {false};
printf("%d", ans[0][0]);
vis[ans[0][0]-1] = true;
for(int i = 1; i < ans[0].size(); i++){
printf(" %d", ans[0][i]);
vis[ans[0][i]-1] = true;
}
puts("");
bool first = true;
for(int i = 0; i < 6; i++){
if(!vis[i] && num[i]){
if(first){
printf("%d", i+1);
first = false;
}
else printf(" %d", i+1);
}
}
}
else{//欧文人数都比亚特少时无解
puts("GG");
return 0;
}
}
}
}
else if(alls.size() == 1){
int i = alls[0];
Output(i);
}
else puts("GG");
return 0;
}
void Output(int i){
vector<int> ans1, ans2;
for(int j = 0; j < 6; j++){
if((i&(1<<j)) && num[j])
ans1.push_back(j+1);
else if(!(i&(1<<j)) && num[j])
ans2.push_back(j+1);
}
printf("%d", ans1[0]);
for(int j = 1; j < ans1.size(); j++)
printf(" %d", ans1[j]);
puts("");
printf("%d", ans2[0]);
for(int j = 1; j < ans2.size(); j++)
printf(" %d", ans2[j]);
}