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;
}
posted @ 2022-07-20 16:51  指引盗寇入太行  阅读(89)  评论(0编辑  收藏  举报