首页 > 其他分享 >Educational Codeforces Round 114 D(搜索剪枝)

Educational Codeforces Round 114 D(搜索剪枝)

时间:2023-01-10 00:44:24浏览次数:70  
标签:剪枝 Educational 排列 cur int sum Codeforces ar que

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;
}

标签:剪枝,Educational,排列,cur,int,sum,Codeforces,ar,que
From: https://www.cnblogs.com/empty-y/p/17038952.html

相关文章

  • CodeForces - 510C Fox And Names
    CodeForces-510CFoxAndNames题解:建图+拓扑排序首先题目想让你按照给定的字符串修改字母表的字母序,我们很容易想到拓扑排序,但是这怎么建图?实际上对于两个输入的字......
  • Educational Codeforces Round 141 (Rated for Div. 2) Different Arrays
    Problem-D-Codeforces题意:给一个长度为n的数组a,下标从2到n-1,每个位置执行一次操作操作:设操作位置为i,$a_{i-1}+=a_i,a_{i+1}-=a_i$,或者$a_{i-1}-=a_i,a_......
  • Educational Codeforces Round 141 (Rated for Div. 2) A-E
    比赛链接A题意给一个数组\(a\),要求重排列以后\(a[i]\neqa[1,i-1]\),其中\(a[1,i-1]\)是前\(i-1\)项和。如果无解则输出NO;否则,给出一个合法的重排列后的\(a......
  • 「Codeforces」寒假训练 2023 #3
    A.StringLCM原题链接#include<bits/stdc++.h>usingnamespacestd;typedeflonglongll;constintN=1e5+10;intq;strings,t;intlens,lent;int_lcm;......
  • Codeforces Round #266 (Div. 2) C. Number of Ways (dp)
    https://codeforces.com/contest/466/problem/C题目大意:数组a由n个整数组成a[1],a[2],...,a[n]。计算将数组中的所有元素分成三个连续部分的方法,以使每个部分中的元素总和......
  • Educational Codeforces Round 141 (Rated for Div. 2) A-C题解
    比赛链接A、MakeitBeautiful一种构造方法:按照从大到小的顺序构造,可以发现前缀和永远大于当前值。但是需要特判存在两个最大值的情况。只需要将最小值与第二位交换位置......
  • Codeforces Round #646 (Div. 2) D交互
    A.OddSelection题意:给定n个数,是否能选k个数和为奇数分析:和为奇数只有一种情况:n个偶数+k个奇数(n任意,k为奇数)枚举奇数个数即可voidsolve(){a=b=......
  • Codeforces Round #842 (Div. 2)(B,D,E)
    CodeforcesRound#842(Div.2)(B,D,E)B题实在是没想到BB这个题大意是给你一个乱序的一到n的数,我们每次可以选择k个数,放到这个数组的最后面,问我们需要最少多少个操作可以......
  • Educational Codeforces Round 141
    A.MakeitBeautiful他想要变美,我们按照题目说的做就行,通过判断我们发现如果在sort一遍后sort(a+1,a+1+n);if(a[1]==a[n]){cout<<"NO"<<"\n";......
  • B. Kolya and Tandem Repeat -- codeforces
    B.KolyaandTandemRepeathttps://codeforces.com/problemset/problem/443/B 思路如果补充字符长度k大于等于s长度,则新的字符串,一份两半,前半分包括s,可能包括部分补......