【补题日记】[2022杭电暑期多校1]B-Dragon slayer

Pro

https://acm.hdu.edu.cn/showproblem.php?pid=7139

Sol

思路还是比较简单的,犯了几个细节错误。

关于坐标加0.5的处理方法:对每个点维护该点的上下左右四条边的情况,从而在搜索的时候按照上一个点来的方向判断那条边点的情况,即不将在方格中心的点强行放到方格顶点,而是根据顶点所连四条边的情况判断是否可以继续搜索。

思路就是直接状压,用1表示该墙存在,0表示不存在,求保证能从起点走到终点的前提下,求0的个数的最小值。

这里犯了个错误,就是将表示状态的数从小到大枚举的时候,如果发现可以了直接就break了,其实不然。即表示状态的十进制数与0的个数之间并不具有单调关系,因此一旦满足条件不能直接break,而是循环完所有的状态后,对0的个数取最小值才为答案。

Code

//By cls1277
#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
#define Fo(i,a,b) for(LL i=(a); i<=(b); i++)
#define Ro(i,b,a) for(LL i=(b); i>=(a); i--)
#define Eo(i,x,_) for(LL i=head[x]; i; i=_[i].next)
#define Ms(a,b) memset((a),(b),sizeof(a))
#define endl '\n'

//const LL maxn = ;
LL n, m, K, xs, ys, xt, yt;
struct Node {
    LL a, b, c, d; // u, d, l, r;
};

struct Map {
    bool u, d, l, r;
} mp[20][20];

struct Que {
    LL x, y; //1u, 2d, 3l, 4r
};
bool vis[20][20];

const int dx[4] = {0, 0, 1, -1};
const int dy[4] = {1, -1, 0, 0};

int main() {
    ios::sync_with_stdio(false);
    cin.tie(nullptr);
    #ifdef DEBUG
    freopen("data.txt","r",stdin);
    #endif
    LL t; cin>>t;
    while(t--) {
        cin>>n>>m>>K;
        vector<Node> e(K+1);
        cin>>xs>>ys>>xt>>yt;
        Fo(i,1,K) {
            LL a, b, c, d; cin>>a>>b>>c>>d;
            if(a>c) swap(a, c);
            if(b>d) swap(b, d);
            e[i] = {a, b, c, d};
        }
        LL len = (1<<K)-1, ans = INT_MAX;
        Fo(k,0,len) {
            Fo(i,0,n) Fo(j,0,m) mp[i][j] = {0, 0, 0, 0}, vis[i][j] = 0;
            Fo(i,1,K) {
                if(((k>>(i-1))&1)==0) continue;
                if(e[i].a==e[i].c) {
                    Fo(j,e[i].b,e[i].d) {
                        if(j==e[i].b) mp[e[i].a][j].u = 1;
                        else if(j==e[i].d) mp[e[i].a][j].d = 1;
                        else mp[e[i].a][j].u = mp[e[i].a][j].d = 1;
                    }
                } else {
                    Fo(j,e[i].a,e[i].c) {
                        if(j==e[i].a) mp[j][e[i].b].r = 1;
                        else if(j==e[i].c) mp[j][e[i].b].l = 1;
                        else mp[j][e[i].b].l = mp[j][e[i].b].r = 1;
                    }
                }
            }
            queue<Que> q; q.push({xs, ys});
            vis[xs][ys] = 1; bool flag = 0;
            while(!q.empty()) {
                Que u = q.front(); q.pop();
                if(u.x==xt&&u.y==yt) {
                    flag = 1;
                    break;
                }
                Fo(i,0,3) {
                    LL tx=u.x+dx[i], ty=u.y+dy[i];
                    if(tx<0||ty<0||tx>=n||ty>=m||vis[tx][ty]) continue;
                    if(i==0&&!mp[tx][ty].r) {
                        vis[tx][ty] = 1;
                        q.push({tx, ty});
                    } else if(i==1&&!mp[u.x][u.y].r) {
                        vis[tx][ty] = 1;
                        q.push({tx, ty});
                    } else if(i==2&&!mp[tx][ty].u) {
                        vis[tx][ty] = 1;
                        q.push({tx, ty});
                    } else if(i==3&&!mp[u.x][u.y].u) {
                        vis[tx][ty] = 1;
                        q.push({tx, ty});
                    }
                }
            }
            if(flag) ans = min(ans, K-__builtin_popcount(k));
        }
        cout<<ans<<endl;
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

cls1277

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值