Educational Codeforces Round 114 D(搜索剪枝)

D. The Strongest Build

题目大意:

给定n个位置,每个位置有c\({_i}\)个可选能力值(能力值升序给出即a\({_1}\) < a\({_2}\) < a\({_3}\) < ... < a\({_{ci}}\)),你可以在每个位置在对应的可选能力值中选一个,最终可以得到一个排列b[],表示在第i个位置选择了第k个能力值,同时题目会禁止m个排列,求选取的能力值之和最大的排列b[]并输出。


解题思路:

由于给定了m个排列不能选择,实际上我们现在需要求的就是第m+1大的排列,所以我们可以据此进行搜索。
由于能力值升序给出,所以最大的能力值排列一定是g[i][len[i]],选择每个位置的最后一个能力值,而次小的就是g[i][len[i]-1]。
如果暴力的搜每个状态无疑是会超时的,但是因为我们只需要搜索前m+1个,所以如果队列的size()大于m+1,我们就要不断的清除队尾排列。
由于我们需要在搜索的时候对排列能力值之和进行排序搜索(每次从最大的开始扩展),同时需要支持清除队尾排列,所以普通的queue不是特别的支持,所以我们需要用set来模拟(支持内部元素按照给定方式排列,支持清除任意位置的元素)
其次对于何时结束:虽然我们猜测的是搜索前m+1大的排列,但是因为有可能题目禁止的不一定是前m大的排列,所以我们在搜索的时候只要搜索到不是题目禁止的排列就是答案(bfs搜索保证了扩展到的一定是当前满足条件的最大值)


代码实现:

#include<bits/stdc++.h>
using namespace std;
# define int long long
# define endl "\n"
const int N = 2e5 + 10, inf = 0x3f3f3f3f;
set<array<int,10>> se;//题目禁止的排列 
int g[15][N];
int len[15];
int n,m;
struct node{
	array<int,10> ar;
	int sum = 0;
	void ini(){
		for(int i = 0;i < 10;++i) ar[i] = 0;
		sum = 0;
	}
	/*重载内部排序方式*/
	bool operator < (const node& nod) const{
		if(sum == nod.sum) return ar>nod.ar;
		return sum>nod.sum;
	}
};
set<node> que;
void solve() {
	cin>>n;
	for(int i = 1;i <= n;++i){
		cin>>len[i];
		for(int j = 1;j <= len[i];++j) cin>>g[i][j];
	}
	cin>>m;
	for(int i = 1;i <= m;++i){
		array<int,10> ar;
		for(int j = 0;j < 10;++j) ar[j] = 0;
		for(int j = 0;j < n;++j) cin>>ar[j];
		se.insert(ar);
	}
	node cur;
	cur.ini();
	/*从最大排列开始搜*/ 
	for(int i = 0;i < n;++i){
		cur.ar[i] = len[i+1];
		cur.sum+=g[i+1][len[i+1]];
	}
	que.insert(cur);
	while(!que.empty()){
		cur = *que.begin();
		que.erase(que.begin());
		if(!se.count(cur.ar)){
			for(int i = 0;i < n;++i){
				cout<<cur.ar[i]<<" \n"[i == n];
			}
			return;
		}
		for(int i = 0;i < n;++i){
			if(cur.ar[i]>1){
				/*如果当前位置有大于1个能力值可选就选择次小入队*/ 
				node net;
				net.sum = 0;
				for(int j = 0;j < 10;++j){
					net.ar[j] = cur.ar[j];
				}
				net.ar[i]--;
				for(int j = 0;j < 10;++j){
					net.sum+=g[j+1][net.ar[j]];
				}
				que.insert(net);
				/*如果超过m+1种排列就去除末尾排列,减小搜索范围*/ 
				while(que.size()>m+1) que.erase(--que.end());
			}
		}
	}
	
}
int tt;
signed main() {
	ios::sync_with_stdio(false);
	cin.tie(0);
	cout.tie(0);
	tt = 1;
//	cin >> tt;
	while (tt--) solve();


	return 0;
}
posted @ 2023-01-10 00:35  empty_y  阅读(71)  评论(0)    收藏  举报