[BZOJ 2150]部落战争(最小路径覆盖、二分图最大匹配)

98 篇文章 0 订阅
41 篇文章 0 订阅

题目链接:http://www.lydsy.com:808/JudgeOnline/problem.php?id=2150

思路:很裸的最小路径覆盖问题,这个问题有两种解法:1、网络流,拆点,2、二分图最大匹配

将每个无障碍的点和它可达的无障碍的点连边,然后跑二分图最大匹配即可。

#include <stdio.h> 
#include <stdlib.h> 
#include <string.h> 
#include <algorithm> 
#include <queue> 
   
#define MAXE 7000000 
#define MAXN 2600 
   
using namespace std; 
   
struct edge 
{ 
    int u,v,next; 
}edges[MAXE]; 
   
char map[55][55];  
   
int n,m,r,c; 
int head[MAXN],nCount=0; 
int linky[MAXN]; 
   
bool visit[MAXN]; 
   
bool inMap(int x,int y) 
{ 
    if(x<1||x>n||y<1||y>m) return false; 
    if(map[x][y]=='x') return false; 
    return true; 
} 
   
int getNum(int x,int y) 
{ 
    return (x-1)*m+y; 
} 
   
void AddEdge(int U,int V) 
{ 
    edges[++nCount].u=U; 
    edges[nCount].v=V; 
    edges[nCount].next=head[U]; 
    head[U]=nCount; 
} 
   
bool dfs(int u) 
{ 
    for(int p=head[u];p!=-1;p=edges[p].next) 
    { 
        int v=edges[p].v; 
        if(visit[v]) continue; 
        visit[v]=true; 
        if(linky[v]==-1||dfs(linky[v])) 
        { 
            linky[v]=u; 
            return true; 
        }  
    } 
    return false; 
}  
   
int main() 
{ 
    int i,j;
    memset(head,-1,sizeof(head)); 
    scanf("%d%d%d%d",&n,&m,&r,&c); 
    for(i=1;i<=n;i++) 
    { 
        char in[MAXN]; 
        scanf("%s",in+1); 
        for(j=1;j<=m;j++) 
            map[i][j]=in[j]; 
    } 
    for(i=1;i<=n;i++) 
        for(j=1;j<=m;j++) 
            if(map[i][j]=='.')
            { 
                if(inMap(i-c,j-r)) AddEdge(getNum(i-c,j-r),getNum(i,j)); 
                if(inMap(i-c,j+r)) AddEdge(getNum(i-c,j+r),getNum(i,j)); 
                if(inMap(i-r,j-c)) AddEdge(getNum(i-r,j-c),getNum(i,j)); 
                if(inMap(i-r,j+c)) AddEdge(getNum(i-r,j+c),getNum(i,j)); 
            } 
    memset(linky,-1,sizeof(linky)); 
    int ans=0,sum=0; 
    for(i=1;i<=n;i++) 
        for(j=1;j<=m;j++) 
        { 
            if(map[i][j]=='.') 
            { 
                memset(visit,false,sizeof(visit)); 
                ans+=dfs(getNum(i,j)); 
                sum++; 
            } 
        } 
    printf("%d\n",sum-ans); 
    return 0; 
}



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值