poj3020 Antenna Placement 题解

题目传送门
题目大意:给出一个包含 *o 的矩阵,其中 * 代表城市 o 代表空地。一个网络基站可以覆盖相邻的两个地方,现在要让所有的城市都覆盖网络,求至少要几个基站。

显然能以 x 坐标和 y 坐标来作为节点,我们需要把每个城市作为节点,然后相邻的城市建一条双向边。
但是我们发现这样不是二分图,所以我们就要拆点,比如说这张图存在两个无向边 (1,2)(2,3) ,就是这样:

然后就可以直接求最小路径覆盖就可以了。
根据公式 无向二分图的最小路径覆盖 = 顶点数 最大匹配数 ÷2 就可以直接求出答案了。
注意定点数是拆点之前的顶点数。

代码:

#include<queue>
#include<cstdio>
#include<cstring>
#define maxt 139
#define maxn 1039
#define maxm 1000039
#define INF 0x7fffffff
#define min(a,b) ((a)<(b)?(a):(b))
using namespace std;
//#define debug
typedef int Type;
inline Type read(){
Type sum=0;
int flag=0;
char c=getchar();
while((c<'0'||c>'9')&&c!='-') c=getchar();
if(c=='-') c=getchar(),flag=1;
while('0'<=c&&c<='9'){
sum=(sum<<1)+(sum<<3)+(c^48);
c=getchar();
}
if(flag) return -sum;
return sum;
}
int fx[5]={0,0,1,-1},fy[5]={1,-1,0,0};
int n,m,cnt,c,tox,toy;
int map[maxt][maxt],f[maxn][maxn];
int s,t,ans,dis[maxn],now[maxn];
int head[maxn],to[maxm],nex[maxm],w[maxm],kkk;
#define add(x,y,z) nex[++kkk]=head[x]; head[x]=kkk; to[kkk]=y; w[kkk]=z;
queue<int> q,E;
int bfs(){
memset(dis,0,sizeof(dis)); q=E; q.push(s);
dis[s]=1; for(int i=1;i<=cnt;i++) now[i]=head[i];
while(!q.empty()){
int cur=q.front(); q.pop();
for(int i=head[cur];i;i=nex[i])
if(!dis[to[i]]&&w[i]>0){
dis[to[i]]=dis[cur]+1; q.push(to[i]);
if(to[i]==t) return 1;
}
}
return 0;
}
int dfs(int x,int sum){
if(x==t) return sum; int res=0,tmp;
for(int i=now[x];i&&sum>0;i=nex[i]){
now[x]=i;
if(dis[x]+1==dis[to[i]]&&w[i]>0){
tmp=dfs( to[i],min(w[i],sum) );
if(tmp==0) dis[to[i]]=0;
w[i]-=tmp; w[i^1]+=tmp; sum-=tmp; res+=tmp;
}
if(!sum) break;
}
return res;
}
void work(){
n=read(); m=read(); cnt=0; kkk=1; memset(head,0,sizeof(head)); memset(f,0,sizeof(f));
for(int i=1;i<=n;i++) for(int j=1;j<=m;j++){
c=getchar(); while(c!='o'&&c!='*') c=getchar();
if(c=='o') map[i][j]=0;
else map[i][j]=++cnt;
}
for(int i=1;i<=n;i++) for(int j=1;j<=m;j++)
if(map[i][j]){
for(int x=0;x<4;x++){
tox=i+fx[x]; toy=j+fy[x];
if(tox<1||tox>n||toy<1||toy>m) continue;
f[map[i][j]][map[tox][toy]]=1;
}
}
s=(cnt<<1)+1; t=(cnt<<1)+2;
for(int i=1;i<=cnt;i++){ add(s,i,1); add(i,s,0); add(i+cnt,t,1); add(t,i+cnt,0); }
for(int i=1;i<=cnt;i++) for(int j=i+1;j<=cnt;j++)
if(f[i][j]){ add(i,j+cnt,1); add(j+cnt,i,0) add(j,i+cnt,1); add(i+cnt,j,0) }
cnt=(cnt<<1)+2; ans=0; while(bfs()) ans+=dfs(s,0x7fffffff);
printf("%d\n",((cnt-2)>>1)-ans/2);
return;
}
int main(){
//freopen("1.in","r",stdin);
//freopen(".out","w",stdout);
int T=read(); while(T--) work();
return 0;
}
posted @   jiangtaizhe001  阅读(41)  评论(0编辑  收藏  举报
编辑推荐:
· 开发者必知的日志记录最佳实践
· SQL Server 2025 AI相关能力初探
· Linux系列:如何用 C#调用 C方法造成内存泄露
· AI与.NET技术实操系列(二):开始使用ML.NET
· 记一次.NET内存居高不下排查解决与启示
阅读排行:
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· AI技术革命,工作效率10个最佳AI工具
点击右上角即可分享
微信分享提示