Problem1:玉米田
Part1:题目分析
通过数据范围(状压DP的时间复杂度是
2
n
2^n
2n)和输入数据(是
0
0
0或
1
1
1)这道题这是一道状压DP的题目,我们可以设计出状态:
d
p
[
i
]
[
s
]
=
第
i
行种植玉米的情况为
s
时的情况数量
dp[i][s] = 第i行种植玉米的情况为s时的情况数量
dp[i][s]=第i行种植玉米的情况为s时的情况数量
那么如何判断合不合法呢?我们先举几个例子:(把第
i
i
i层的
s
s
s记作
s
i
si
si)
第
i
i
i层的
s
s
s是
10
10
10
第
i
+
1
i + 1
i+1层的
s
s
s是
11
11
11
合不合法呢?
我们把它们装成二进制看一下:
1010
1010
1010
1011
1011
1011
很明显是不合法的,通过分析,我们得出如下结论:
上下层的判断:
s
i
si
si &
s
i
+
1
>
0
si+1 > 0
si+1>0 就是不合法;
左右的判断:
s
i
si
si &
(
s
i
>
>
1
)
>
0
(si>>1)>0
(si>>1)>0就是不合法。
Part2:代码
根据分析,我们可以得出如下代码:
#include <iostream>
#include <vector>
using namespace std;
const int N = 14, M = 1 << N, mod = 1e8;
int n, m, k;
int g[N];
int f[N][M];
vector<int> state;
vector<int> head[M];
bool check(int state)
{
return !(state & state << 1);
}
int main()
{
cin >> n >> m;
for (int i = 1; i <= n; ++ i)
for (int j = 0; j < m; ++ j)
cin >> k, g[i] |= !k << j;
for (int st = 0; st < 1 << m; ++ st)
if (check(st))
state.push_back(st); //预处理合法状态
for (auto st: state)
for (auto ne_st: state)
if (!(st & ne_st))
head[st].push_back(ne_st); //预处理合法状态的合法转移
f[0][0] = 1;
for (int i = 1; i <= n + 1; ++ i)
for (auto st: state)
if (!(st & g[i]))
for (auto pre_st: head[st])
f[i][st] = (f[i][st] + f[i - 1][pre_st]) % mod;
cout << f[n + 1][0] << endl;
return 0;
}
Problem2:皇宫看守
Part1:题目分析
Part2:代码
#include<bits/stdc++.h>
using namespace std;
#define endl '\n'
#define int long long
#define PII pair<int, int>
#define For(i, a, b) for(int i = a;i <= b;i++)
const int N = 1e4 + 1000;
int f[N][3];
int in[N];
int h[N], e[N], ne[N], idx;
int n;
void add(int a, int b){
e[idx] = b, ne[idx] = h[a], h[a] = idx++;
}
void dfs(int u){
f[u][0] = 0;
f[u][1] = 0x3f3f3f3f3f3f3f3f;
f[u][2] = w[u];
for (int i = h[u]; ~i;i = ne[i]){
int j = e[i];
dfs(j);
f[u][0] += min({f[j][0], f[j][1], f[j][2]});
}
for (int i = h[u]; ~i;i = ne[i]){
int j = e[i];
f[u][1] = min(f[u][1], f[j][2] + f[u][0] - min(f[j][1], f[j][2]));
}
}
signed main(){
ios::sync_with_stdio(false), cin.tie(0), cout.tie(0);
memset(h, -1, sizeof h);
cin >> n;
For (i, 1, n){
int x, m;
cin >> x >> w[x] >> m;
while (m--){
int y;
cin >> y;
add(x, y);
in[y]++;
}
}
int root = 1;
while (in[root])
root++;
dfs(root);
cout << min(f[root][1], f[root][2]);
return 0;
}
Problem3:骑士
这道题就作为课后练习啦,大家自行思考。
结语
今天的文章就到这里啦,三连必回哦。