BZOJ4554: [Tjoi2016&Heoi2016]游戏

Description

在2016年,佳缘姐姐喜欢上了一款游戏,叫做泡泡堂。简单的说,这个游戏就是在一张地图上放上若干个炸弹,看
是否能炸到对手,或者躲开对手的炸弹。在玩游戏的过程中,小H想到了这样一个问题:当给定一张地图,在这张
地图上最多能放上多少个炸弹能使得任意两个炸弹之间不会互相炸到。炸弹能炸到的范围是该炸弹所在的一行和一
列,炸弹的威力可以穿透软石头,但是不能穿透硬石头。给定一张n*m的网格地图:其中*代表空地,炸弹的威力可
以穿透,可以在空地上放置一枚炸弹。x代表软石头,炸弹的威力可以穿透,不能在此放置炸弹。#代表硬石头,炸
弹的威力是不能穿透的,不能在此放置炸弹。例如:给出1*4的网格地图*xx*,这个地图上最多只能放置一个炸弹
。给出另一个1*4的网格地图*x#*,这个地图最多能放置两个炸弹。现在小H任意给出一张n*m的网格地图,问你最
多能放置多少炸弹

Input

第一行输入两个正整数n,m,n表示地图的行数,m表示地图的列数。1≤n,m≤50。接下来输入n行m列个字符,代表网
格地图。*的个数不超过n*m个

Output

输出一个整数a,表示最多能放置炸弹的个数

Sample Input

4 4
#∗∗∗
∗#∗∗
∗∗#∗
xxx#

Sample Output

5
 
经典题了,遇到#号把行列拆开然后二分图匹配。
粘错模板WA了一发QAQ。
#include<cstdio>
#include<cctype>
#include<queue>
#include<cstring>
#include<algorithm>
#define rep(i,s,t) for(int i=s;i<=t;i++)
#define dwn(i,s,t) for(int i=s;i>=t;i--)
#define ren for(int i=first[x];i!=-1;i=next[i])
using namespace std;
const int maxn=3010;
const int maxm=50010;
const int inf=1e9;
struct ISAP{
    struct tedge{int x,y,w,next;}adj[maxm];int ms,fch[maxn];
    int d[maxn],s[maxn],cur[maxn],gap[maxn],n,top;
    void init(){
        ms=0;top=0;
        memset(d,-1,sizeof(d));
        memset(fch,-1,sizeof(fch));
    }
    void AddEdge(int u,int v,int w){
        adj[ms]=(tedge){u,v,w,fch[u]};fch[u]=ms++;
        adj[ms]=(tedge){v,u,0,fch[v]};fch[v]=ms++;
    }
    void bfs(){
        queue<int>Q;Q.push(n);d[n]=0;
        while(!Q.empty()){
            int u=Q.front();Q.pop();
            for(int i=fch[u];i!=-1;i=adj[i].next){
                int v=adj[i].y;
                if(d[v]==-1) d[v]=d[u]+1,Q.push(v);
            }
        } 
    }
    int solve(int S,int T){
        n=T;bfs();int k=S,i,flow=0;
        for(i=0;i<=n;i++) cur[i]=fch[i],gap[d[i]]++;
        while(d[S]<n){
            if(k==n){
                int mi=inf,pos;
                for(i=0;i<top;i++) if(adj[s[i]].w<mi) mi=adj[s[i]].w,pos=i;
                for(i=0;i<top;i++) adj[s[i]].w-=mi,adj[s[i]^1].w+=mi;
                flow+=mi;top=pos;k=adj[s[top]].x;
            }
            for(i=cur[k];i!=-1;i=adj[i].next){
                int v=adj[i].y;
                if(adj[i].w&&d[k]==d[v]+1){cur[k]=i;k=v;s[top++]=i;break;}
            }
            if(i==-1){
                int lim=n;
                for(i=fch[k];i!=-1;i=adj[i].next){
                    int v=adj[i].y;
                    if(adj[i].w&&d[v]<lim) lim=d[v],cur[k]=i;
                } if(--gap[d[k]]==0) break;
                d[k]=lim+1;gap[d[k]]++;
                if(k!=S) k=adj[s[--top]].x;
            }
        } return flow;
    }
}sol;
char Map[55][55];
int n,m,S,T,A[55][55],B[55][55];
int main() {
	scanf("%d%d",&n,&m);
	rep(i,1,n) scanf("%s",Map[i]+1);sol.init();
	rep(i,1,n) {
		S++;
		rep(j,1,m) {
			if(Map[i][j]=='#') S++;
			A[i][j]=S;
		}
	}
	rep(j,1,m) {
		S++;
		rep(i,1,n) {
			if(Map[i][j]=='#') S++;
			B[i][j]=S;
		}
	}
	S++;T=S+1;sol.n=T;
	rep(i,1,A[n][m]) sol.AddEdge(S,i,1);
	rep(i,A[n][m]+1,B[n][m]) sol.AddEdge(i,T,1);
	rep(i,1,n) rep(j,1,m) if(Map[i][j]=='*') sol.AddEdge(A[i][j],B[i][j],1);
	printf("%d
",sol.solve(S,T));
	return 0;
}

  

原文地址:https://www.cnblogs.com/wzj-is-a-juruo/p/5506332.html