LOJ #3207. 「BalticOI 2019 Day2」奥运会(A*+贪心)

https://loj.ac/problem/3207

题解:

这个题和前前博客的思路类似,都是利用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);
		}
	}
}
posted @ 2020-05-27 21:18  Cold_Chair  阅读(322)  评论(0编辑  收藏  举报