LOJ #3207. 「BalticOI 2019 Day2」奥运会(A*+贪心)
题解:
这个题和前前博客的思路类似,都是利用A*去扩展。
但是这题比较难找一种扩展方法,一开始我写了一种很复杂的扩展方法。
后来在zsy博客上看到简单的:
一个状态定义为:
确定了一个前缀,每个位置选谁作为最大值(位置选的互不相同,注意一个位置的代表位置不一定就是这个位置最大的)。
估价就是后面也填最大的。
暴力就是一位位扩展,应该是\(O(n^2*k^2*C)\)个状态。
还是考虑跨着扩展,多记一个bitset表示哪些能选,就优化到\(O(n*k^2C)\)了。
Code:
#include<bits/stdc++.h>
#define fo(i, x, y) for(int i = x, _b = y; i <= _b; i ++)
#define ff(i, x, y) for(int i = x, _b = y; i < _b; i ++)
#define fd(i, x, y) for(int i = x, _b = y; i >= _b; i --)
#define ll long long
#define pp printf
#define hh pp("\n")
using namespace std;
const int N = 505;
int n, k, c;
int a[N][7];
struct nod {
bitset<N> bz;
int pos, val;
int p[7];
};
bool operator < (nod a, nod b) {
return a.val < b.val;
}
priority_queue<nod> q;
void add(nod x) {
static int mx[7];
fo(i, 1, k) mx[i] = 0;
fo(i, 1, x.pos) fo(j, 1, k) mx[j] = max(mx[j], a[x.p[i]][j]);
fo(j, x.pos + 1, k) {
int id = -1, ms = -1e9;
fo(i, 1, n) if(!x.bz[i]) {
if(a[i][j] > ms) {
id = i, ms = a[i][j];
}
}
if(id == -1) return;
x.bz[id] = 1;
x.p[j] = id;
fo(i, 1, k) mx[i] = max(mx[i], a[id][i]);
}
x.val = 0;
fo(j, 1, k) x.val += mx[j];
q.push(x);
}
int main() {
scanf("%d %d %d", &n, &k, &c);
fo(i, 1, n) fo(j, 1, k) scanf("%d", &a[i][j]);
nod z; z.pos = 0; add(z);
for(; c; c --) {
nod x = q.top(); q.pop();
if(c == 1) {
pp("%d\n", x.val);
break;
}
fo(i, x.pos + 1, k) {
nod y = x;
y.pos = i - 1;
fo(j, i + 1, k) y.bz[y.p[j]] = 0;
add(y);
}
}
}
转载注意标注出处:
转自Cold_Chair的博客+原博客地址