2022杭电多校第一场部分题解
Dragon slayer
题解:
解法1:可以二进制枚举当前存在哪些墙,然后bfs;
解法2:可以观察到只有删掉墙才会有贡献,相当于边权为1,其他情况边权为0,采用状压01bfs
代码:
#include <bits/stdc++.h>
//#define int long long
int _ = 0, Case = 1;
using namespace std;
#define all(v) begin(v),end(v)
#define nline '\n'
#define SZ(v) (int) v.size()
const int N = 16;
int d[N][N][1 << 15];
struct T {
int x1, y1, x2, y2;
} wall[N];
int n, m, k;
int sx, sy, tx, ty;
struct TT {
int x, y, st;
};
bool vis[N][N][1 << 15];
pair<int, int> moves[] = {{ -1, 0}, {0, -1}, {0, 1}, {1, 0}}; //ULRD
bool check(int nx, int ny, int x, int y, int k, int dir) {
double x1 = wall[k].x1 , y1 = wall[k].y1 ;
double x2 = wall[k].x2 , y2 = wall[k].y2 ;
if (dir == 1) {
if (x1 == x2 and nx == x1 and x == x1 - 1) {
if (y < min(y1, y2)) return false;
if (y >= max(y1, y2)) return false;
return true;
}
} else if (dir == 2) {
if (y1 == y2 and ny == y1 and y == ny - 1) {
if (x < min(x1, x2)) return false;
if (x >= max(x1, x2)) return false;
return true;
}
} else if (dir == 3) {
if (y1 == y2 and y == y1 and ny == y1 - 1) {
if (x < min(x1, x2)) return false;
if (x >= max(x1, x2)) return false;
return true;
}
} else {
if (x1 == x2 and x == x1 and nx == x1 - 1) {
if (y < min(y1, y2)) return false;
if (y >= max(y1, y2)) return false;
return true;
}
}
return false;
}
int bfs() {
memset(d, 0x3f, sizeof d);
memset(vis, 0, sizeof vis);
deque<TT> q;
q.push_front({sx, sy, (1 << k) - 1});
d[sx][sy][(1 << k) - 1] = 0;
while (q.size()) {
auto t = q.front();
q.pop_front();
int x = t.x, y = t.y, st = t.st;
if (vis[x][y][st]) continue;
vis[x][y][st] = 1;
int cnt = 0;
for (auto ds : moves) {
int dx = ds.first, dy = ds.second;
int tx = dx + x, ty = dy + y;
cnt++;
if (tx >= 0 and tx < n and ty >= 0 and ty < m ) {
int step = 0;
int newst = st;
for (int k = 0; k < 15; k++) {
if (st >> k & 1) {
if (check(x, y, tx, ty, k + 1, cnt)) {
step++;
newst -= (1LL << k);
}
}
}
if (step) {
d[tx][ty][newst] = d[x][y][st] + step;
q.push_back({tx, ty, newst});
} else {
d[tx][ty][newst] = d[x][y][st] + step;
q.push_front({tx, ty, newst});
}
}
}
}
int ans = 2e9;
for (int i = 0; i < 1 << k; i++) {
ans = min(ans, d[tx][ty][i]);
}
return ans;
}
void solve(int Case) {
cin >> n >> m >> k;
cin >> sx >> sy >> tx >> ty;
for (int i = 1; i <= k; i++) {
cin >> wall[i].x1 >> wall[i].y1 >> wall[i].x2 >> wall[i].y2;
}
cout << bfs() << nline;
}
signed main() {
ios::sync_with_stdio(false); cin.tie(nullptr);
for (cin >> _, Case = 1; Case <= _; Case++)
solve(Case);
return 0;
}
Backpack
思路:
先考虑最基础的dp,\(f[i][j][k]\)表示前i个物品,异或和为j,体积为k的方案是否存在,\(f[i][j][k]=f[i-1][j][k]|f[i-1][j xor w[i]][k-v[i]]\)
然后考虑优化,因为只有01两种状态,使用bitset优化,\(f[i][j]\)表示前i个物品,异或和为j的bitset,bitset里面对应的第k个位置如果是1,
就相当于体积恰好为k的状态是1,因为k由第\(i-1\)的\(k-v[i]\)转移过来,所以把\(f[i][j xor w[i]]\)的状态左移\(v[i]\)然后跟\(f[i-1][j]\)取异或即可
代码:
#include <bits/stdc++.h>
#define int long long
int _ = 0, Case = 1;
using namespace std;
#define all(v) begin(v),end(v)
#define nline '\n'
#define SZ(v) (int) v.size()
const int N = 1100;
bitset<N> f[N], g[N];
int w[N], v[N];
void solve(int Case) {
int n, m;
cin >> n >> m;
for (int i = 1; i <= n; i++) cin >> v[i] >> w[i];
for (int i = 0; i < N; i++) {
f[i].reset();
g[i].reset();
}
f[0][0] = 1;
for (int i = 1; i <= n; i++) {
for (int j = 0; j < N; j++) {
if ((j ^ w[i]) < N) {
g[j] = f[j];
auto cur = f[j ^ w[i]];
cur <<= v[i];
g[j] |= cur;
}
}
for (int j = 0; j < N; j++) {
f[j] = g[j];
}
}
int ans = -1;
for (int i = 0; i < N; i++) {
if (f[i][m]) ans = max(ans, i);
}
cout << ans << nline;
}
signed main() {
ios::sync_with_stdio(false); cin.tie(nullptr);
for (cin >> _, Case = 1; Case <= _; Case++)
solve(Case);
return 0;
}