poj3020 Antenna Placement 题解
题目传送门
题目大意:给出一个包含 *
和 o
的矩阵,其中 *
代表城市 o
代表空地。一个网络基站可以覆盖相邻的两个地方,现在要让所有的城市都覆盖网络,求至少要几个基站。
显然能以 坐标和 坐标来作为节点,我们需要把每个城市作为节点,然后相邻的城市建一条双向边。
但是我们发现这样不是二分图,所以我们就要拆点,比如说这张图存在两个无向边 和 ,就是这样:
然后就可以直接求最小路径覆盖就可以了。
根据公式 无向二分图的最小路径覆盖 顶点数 最大匹配数 就可以直接求出答案了。
注意定点数是拆点之前的顶点数。
代码:
#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; }
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 开发者必知的日志记录最佳实践
· 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工具