P1263

题意

给出一个 \(m \times n\) 的矩阵,有空地、墙、陷阱三种情况。

只有空地可以放置守卫,若两个守卫在同一行或同一列且其之间没有墙的阻挡则这两个守卫可以互相看见。

求最多可以放置的守卫数,并输出一种放置方案。

题解

其实这题和 P2825 几乎一致,墙的存在让行、列分段,各段之间互不干扰。

所以可以把每个部分看成一个点,即把连续的一段缩成一个点并编号。

然后把可以放置的点的位置的行、列坐标连边,跑二分图最大匹配即可。

题目要求输出方案,就利用匈牙利算法的特性,把编号与行列对应即可。

代码

#include <bits/stdc++.h>
#define V e[i].v
using namespace std;const int N=2e3,M=1e6;int n,m,a[N][N],in[N][N],out[N][N],t,c,ans,F[M],f[N],p[M];
struct E{int v,nt;}e[M];void I(int u,int v){e[++c].v=v;e[c].nt=F[u];F[u]=c;}
int dfs(int x){for(int i=F[x];i;i=e[i].nt)if(!f[V]){f[V]=1;if(!p[V]||dfs(p[V])){p[V]=x;return 1;}}return 0;}
int main(){
    cin>>n>>m;for(int i=1;i<=n;i++)for(int j=1;j<=m;j++)cin>>a[i][j];
    for(int i=1;i<=n;i++)for(int j=1;j<=m;j++)if(a[i][j]!=2){if(j==1||a[i][j-1]==2)	t++;in[i][j]=t;}
    for(int j=1;j<=m;j++)for(int i=1;i<=n;i++)if(a[i][j]!=2){if(i==1||a[i-1][j]==2)	t++;out[i][j]=t;}
    for(int i=1;i<=n;i++)for(int j=1;j<=m;j++)if(!a[i][j])I(in[i][j],out[i][j]);
    for(int i=1;i<=t;i++)memset(f,0,sizeof(f)),ans+=dfs(i);cout<<ans<<endl;
    for(int i=1;i<=n;i++)for(int j=1;j<=m;j++)if(p[out[i][j]]==in[i][j]&&!a[i][j])cout<<i<<" "<<j<<endl;return 0;
}
posted @ 2022-02-25 21:34  AIskeleton  阅读(31)  评论(0编辑  收藏  举报