给定n个位置,每个位置有c\({_i}\)个可选能力值(能力值升序给出即a\({_1}\) < a\({_2}\) < a\({_3}\) < ... < a\({_{ci}}\)),你可以在每个位置在对应的可选能力值中选一个,最终可以得到一个排列b[],表示在第i个位置选择了第k个能力值,同时题目会禁止m个排列,求选取的能力值之和最大的排列b[]并输出。 由于给定了m个排列不能选择,实际上我们现在需要求的就是第m+1大的排列,所以我们可以据此进行搜索。D. The Strongest Build
题目大意:
解题思路:
由于能力值升序给出,所以最大的能力值排列一定是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;
}