题解:P10945 Place the Robots
P10945 题解
题面
思路
看到这一题,想到二分图。
但是这题的建图还需要仔细思考一下。
发现这道题的墙就和网格的边界一样,阻挡激光,所以不免可以把一行拆成由墙隔开的多行,一列拆成由墙隔开的多列。
于是我们不妨把可以放置激光的位置的属于拆过之后的行和拆过之后的列连边,由于拆过之后的行和列每一行,每一列都只选一个,所以就可以跑二分图最大匹配即可。
代码
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
//#define gc getchar
#define gc()(p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<21,stdin),p1==p2)?EOF:*p1++)
#define ll long long
using namespace std;
const int MN=55,MM=5e5+5;
ll n,m,h[MN][MN],l[MN][MN],mp[MN][MN],tot,head[MM],y[MM],used[MM],tm,l1,l2,ans;
char buf[1<<23],*p1=buf,*p2=buf;
struct edge{ll to,nxt;}e[MM<<1];
void write(ll n){if(n<0){putchar('-');write(-n);return;}if(n>9)write(n/10);putchar(n%10+'0');}
ll read(){ll x=0,f=1;char ch=gc();while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=gc();}while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+(ch^48);ch=gc();}return x*f;}
char getc(){char ch=gc();while(ch!='*'&&ch!='o'&&ch!='#')ch=gc();return ch;}
void init(){l1=l2=tm=tot=ans=0;for(int i=1; i<=n*m; i++)head[i]=y[i]=used[i]=0;}
void add(ll u, ll v){e[++tot].nxt=head[u];head[u]=tot;e[tot].to=v;}
bool find(ll u){
for(int i=head[u]; i; i=e[i].nxt){
ll v=e[i].to;
if(used[v]!=tm){
used[v]=tm;
if(!y[v]||find(y[v])){
y[v]=u;
return true;
}
}
}
return false;
}
void solve(ll cn){
putchar('C');putchar('a');putchar('s');putchar('e');putchar(' ');putchar(':');write(cn);putchar('\n');
n=read();m=read();init();
for(int i=1; i<=n; i++) for(int j=1; j<=m; j++){
char ch=getc();
mp[i][j]=ch=='*'?2:ch=='#'?0:1;
}
for(int i=1; i<=n; i++) for(int j=1; j<=m; j++) if(!mp[i][j-1]) h[i][j]=++l1;else h[i][j]=l1;
for(int j=1; j<=m; j++) for(int i=1; i<=n; i++) if(!mp[i-1][j]) l[i][j]=++l2;else l[i][j]=l2;
for(int i=1; i<=n; i++) for(int j=1; j<=m; j++) if(mp[i][j]==1) add(h[i][j],l[i][j]);
for(int i=1; i<=l1; i++){tm++;ans+=find(i);}
write(ans);putchar('\n');
}
int main(){
//ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
ll T=read();for(int i=1; i<=T; i++)solve(i);
return 0;
}//250525

浙公网安备 33010602011771号