题目
题目链接:http://hihocoder.com/problemset/problem/1271
题目来源:hiho的比赛。
简要题意:给定对空和对舰的飞机还有一个航母,给定计算公式,要你弄个奇怪的方案。
题解
题意非常扭曲,但是的确算是个好题吧。
对于 30% 的数据,可以进行搜索,枚举每个位置放哪个飞机。
对于大数据可以采用状压dp的方式。
最多 16 个位置,状态空间为 216 。
由于题目中的限制,你无法直接去算整个结果。
可以分别计算两边的最大值然后再进行一个最后的判断。
dp[i][j] 表示前 i 个对?飞机,位置使用状况为
j 的最大对?伤害。搞完之后根据题目之中的条件进行一个判断就可以了。
需要注意的是如果直接这么做还是无法通过所有数据的。
可以发现任何位置对同种的伤害越大越好。
于是可以排序,只留下最大的 n×m 个对空,对舰的然后去做。
开始直接搞,没贪心各种WA,TLE一晚上,第二天醒来就想明白了。
题目本身还是非常不错的,代码量还是有点长。
代码
#include <iostream>
#include <cstdio>
#include <cmath>
#include <algorithm>
#include <cstring>
#include <stack>
#include <queue>
#include <string>
#include <vector>
#include <set>
#include <map>
#define fi first
#define se second
using namespace std;
typedef long long LL;
typedef pair<int,int> PII;
typedef pair<LL,LL> PLL;
// head
const int N = 10;
const int T = 1005;
const int M = 1 << 16;
const int INF = -1;
int a[N][N];
vector<int> b, c;
vector<PII> d;
int dp[2][M];
int res[2][M];
bool exist = false;
bool yes = false;
int ans = 0;
int n, m, t, s, tt, x, nm, mx;
bool ck(int st) {
int temp[5];
memset(temp, 0, sizeof temp);
for (int i = 0; i < (n*m); i++) {
if ((1 << i) & st) {
temp[d[i].fi] = true;
}
}
for (int i = 0; i < n; i++) {
if (!temp[i]) return false;
}
return true;
}
void getRes(int *tar, const vector<int> &v) {
memset(dp, INF, sizeof dp);
dp[0][0] = 0;
int cur = 1, pre = 0;
for (int i = 0; i < v.size(); i++) {
for (int j = 0; j < mx; j++) {
if (dp[pre][j] == INF) continue;
dp[cur][j] = max(dp[cur][j], dp[pre][j]);
for (int k = 0; k < nm; k++) {
if ((1 << k) & j) continue;
int nxt = j | (1<<k);
dp[cur][nxt] = max(dp[cur][nxt], dp[pre][j] + a[d[k].fi][d[k].se] * v[i]);
}
}
swap(cur, pre);
}
memcpy(tar, dp[pre], sizeof dp[pre]);
}
void solve() {
getRes(res[0], b);
getRes(res[1], c);
for (int i = 0; i < mx; i++) {
if (res[0][i] < s) continue;
exist = true;
int cur = (mx-1) ^ i;
if (res[1][cur] < ans) continue;
if (res[1][cur] > ans) {
ans = res[1][cur];
yes = false;
}
if (ck(cur)) {
yes = true;
}
}
}
void input(vector<int> &b) {
for (int i = 0; i < t; i++) {
scanf("%d", &x);
if (x) b.push_back(x);
}
sort(b.begin(), b.end());
reverse(b.begin(), b.end());
while (b.size() > d.size()) {
b.pop_back();
}
}
int main() {
scanf("%d", &tt);
while (tt--) {
scanf("%d%d%d%d", &n, &m, &t, &s);
nm = n * m;
mx = 1 << nm;
for (int i = 0; i < n; i++) {
for (int j = 0; j < m; j++) {
scanf("%d", a[i]+j);
d.push_back(make_pair(i, j));
}
}
input(b);
input(c);
exist = yes = false;
ans = 0;
solve();
if (!exist) {
puts("Not Exist");
} else {
printf("%d\n%s\n", ans, (yes ? "Yes" : "No"));
}
d.clear();
b.clear();
c.clear();
}
return 0;
}