[HEOI2016/TJOI2016]游戏

壹、题目

传送门

贰、思考

两个炸弹不能同在一行一列,除非有硬石头 # 隔开。软石头 x 不能放东西,也挡不住炸弹 真没用

如果没有硬石头,那么如果有个炸弹能放在 \(\lang x,y\rang\),就 \(x\rightarrow y\) 连一条边,边数有 \(n^2\) 条,点有 \(n\) 个,可以直接跑匈牙利.

但是现在有硬石头了,它可以挡住炸弹,建虚点?但是有另外的问题.

叁、题解

我们单横着看,一个硬石头将两段分开,变成了独立的两段,竖着看,硬石头的效果也是一样,所以我们可以考虑将这一段看成一个点,横竖分开编号。

如果我们在横竖相交的两段的那个点上放炸弹,就相当于是横着这一段的点编号向竖着的点连向一条边,所以我们将点编号之后,对于空着点横连竖,然后跑匈牙利就可以了。

肆、代码

using namespace Elaina;

const int maxn=50;

char maze[maxn+5][maxn+5];

int idx[maxn+5][maxn+5],idy[maxn+5][maxn+5];

int n,m;

inline void input(){
    n=readin(1),m=readin(1);
    rep(i,1,n)scanf("%s",maze[i]+1);
}

int cntx,cnty;
inline void getid(){
    cntx=1;
    rep(i,1,n){
        int j=1;
        while(j<=m){
            if(maze[i][j]=='#'){++j;continue;}
            while(j<=m && maze[i][j]!='#')idx[i][j++]=cntx;
            ++cntx;
        }
    }
    cnty=1;
    rep(j,1,m){
        int i=1;
        while(i<=n){
            if(maze[i][j]=='#'){++i;continue;}
            while(i<=n && maze[i][j]!='#')idy[i++][j]=cnty;
            ++cnty;
        }
    }
}

const int maxnode=2500;
struct edge{int to,nxt;}e[maxnode*maxnode+5];
int tail[maxnode+5],ecnt;
inline void add_edge(const int u,const int v){
    e[++ecnt]=edge{v,tail[u]};tail[u]=ecnt;
}
int bu[maxnode+5][maxnode+5];

inline void buildg(){
    rep(i,1,n)rep(j,1,m)if(maze[i][j]=='*'){
        int u=idx[i][j],v=idy[i][j];
        if(!bu[u][v])add_edge(u,v),bu[u][v]=1;
    }
}

int vis[maxnode+5],match[maxnode+5];
int hungary(const int u){
    for(int i=tail[u],v;i;i=e[i].nxt)if(!vis[v=e[i].to]){
        vis[v]=1;
        if(!match[v] || hungary(match[v])){
            match[v]=u;
            return 1;
        }
    }
    return 0;
}
inline void solve(){
    int ans=0;
    rep(i,1,cntx){
        memset(vis+1,0,cnty<<2);
        if(hungary(i))++ans;
    }
    writc(ans,'\n');
}

signed main(){
    input();
    getid();
    // puts("finished getid()");
    // printf("cntx == %d, cnty == %d\n",cntx,cnty);
    buildg();
    // puts("finished build");
    solve();
    return 0;
}

伍、用到の一些小 \(\tt trick\)

考虑转换模型,对于这种有一个点完全将两段隔开,可以将两段分别看成两个点.

posted @ 2021-02-04 20:08  Arextre  阅读(38)  评论(0编辑  收藏  举报