[模拟]攻略分队 2022RoboCom省赛D

副本是游戏里的一个特色玩法,主要为玩家带来装备、道具、游戏资源的产出,满足玩家的游戏进程。

在 MMORPG《最终幻想14》里,有一个攻略人数最大达到 56 人的副本“巴尔德西昂兵武塔”,因为有在副本里死亡不能复活、机制比较整蛊等特点,一度被玩家视作洪水猛兽。

在副本的开始,我们会遇到第一个难关:攻略的玩家要分为两组,同时讨伐副本 BOSS “欧文”和“亚特”。

已知以下信息:

  1. 玩家会组成 6 支队伍进入副本,其中第 i 队有 Vi​ 位玩家(i=1,⋯,6)。
  2. 每支队伍可能会有一些特殊角色:MT(主坦克)、工兵(负责探测陷阱)和指挥(负责指挥玩家)。

我们的任务是合理安排玩家的分组,以最大程度增加副本通过概率。分组的原则如下:

  1. 要将所有队伍分成 2 组,每支队伍必须且仅属于其中一组;
  2. 每组必须有至少一个 MT(主坦克)。

如果满足上述原则的分组方案不唯一,则按照下列规则确定唯一解:

  1. 优先选择每组有至少一个指挥和至少一个工兵的方案;
  2. 如果规则 1 无法满足,则优先选择每组至少有一个指挥的方案;
  3. 如果所有方案都不满足规则 2,或经过前 2 个规则筛选后,分组方案仍不唯一,则选择两边人数尽可能接近(即两边人数差尽可能小)的方案;
  4. 如果满足规则 3 的方案还不唯一,选择讨伐“欧文”的人数大于等于讨伐“亚特”的人数的方案;
  5. 如果满足规则 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]);
}

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值