题目:292. 炮兵阵地
分析:
- 状态表示:dp[i][j][k]表示考虑前i行,且第i行的状态为j,第k行的状态为k的情况下的部署最大值。
- 状态计算:dp[i][j][k] = max(dp[i][j][k], dp[i - 1][k][u](j, k, u分别为当前行,当前行的上一行,当前行的上两行,且j, k, u均不能互相伤害)
代码:
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
//typedef __int128 lll;
#define print(i) cout << "debug: " << i << endl
#define close() ios::sync_with_stdio(0), cin.tie(0), cout.tie(0)
#define mem(a, b) memset(a, b, sizeof(a))
const ll mod = 1e9 + 7;
const int maxn = 110, maxm = 1 << 12;
const int inf = 0x3f3f3f3f;
int dp[2][maxm][maxm];
int cnt[maxm];
vector<int> state;
int land[maxm];
int n, m;
int calc(int x)
{
int res = 0;
for(int i = 0; i < 20; i++)
if(x & (1 << i))
res++;
return res;
}
void init()
{
for(int i = 0; i < (1 << m); i++)
{
if(i & (i << 2) || i & (i << 1)) continue;
else state.push_back(i), cnt[i] = calc(i);
}
}
int main()
{
cin >> n >> m; getchar();
init();
for(int i = 1; i <= n; i++)
{
for(int j = 1; j <= m; j++)
{
char x; cin >> x;
land[i] <<= 1;
if(x == 'H') land[i] += 1;
}
}
for(int i = 1; i <= n + 2; i++)
for(int j : state)
for(int k : state)
for(int u : state)
{
if((j & k) || (k & u) || (u & j)) continue;
if((j & land[i]) || (k & land[i - 1])) continue;
dp[i & 1][j][k] = max(dp[i & 1][j][k], dp[(i - 1) & 1][k][u] + cnt[j]);
}
cout << dp[(n + 2) & 1][0][0] << endl;
}
题目:524. 愤怒的小鸟
分析:
先求出任意两点与源点构成的抛物线穿过的猪(用state表示)
然后从0到(1 << n) - 1枚举状态(注意,此时枚举的状态已经计算完成,所以可以用来计算其他状态),对于当前状态state,我们枚举穿过state中不包含的一个猪的抛物线,然后更新其他状态。
注意:抛物线开口必须向下
代码:
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
//typedef __int128 lll;
#define print(i) cout << "debug: " << i << endl
#define close() ios::sync_with_stdio(0), cin.tie(0), cout.tie(0)
#define mem(a, b) memset(a, b, sizeof(a))
#define x first
#define y second
typedef pair<double, double> par;
const ll mod = 1e9 + 7;
const int maxn = 20;
const int inf = 0x3f3f3f3f;
par a[maxn];
int path[maxn][maxn];
int dp[1 << maxn];
const double eps = 1e-8;
int cmp(double a, double b)
{
if(fabs(a - b) < eps) return 0;
if(a < b) return -1;
return 1;
}
int main()
{
int t; cin >> t;
while(t--)
{
int n, q; cin >> n >> q;
for(int i = 0; i < n; i++) cin >> a[i].x >> a[i].y;
mem(path, 0);
for(int i = 0; i < n; i++)
{
path[i][i] = 1 << i;
for(int j = 0; j < n; j++)
{
double x1 = a[i].x, y1 = a[i].y;
double x2 = a[j].x, y2 = a[j].y;
if(!cmp(x1, x2)) continue;
double aa = (y1 / x1 - y2 / x2) / (x1 - x2);
if(aa >= 0) continue;
double b = y1 / x1 - aa * x1;
int state = 0;
for(int k = 0; k < n; k++)
{
double x3 = a[k].x;
double y3 = a[k].y;
if(!cmp(aa * x3 * x3 + b * x3, y3))
state |= (1 << k);
}
path[i][j] = state;
}
}
mem(dp, inf);
dp[0] = 0;
for(int i = 0; i < (1 << n) - 1; i++)
{
int pos = 0;
for(int j = 0; ; j++)
if(((1 << j) & i) == 0)
{
pos = j;
break;
}
for(int j = 0; j < n; j++)
dp[i | path[pos][j]] = min(dp[i | path[pos][j]], dp[i] + 1);
}
cout << dp[(1 << n) - 1] << endl;
}
}