poj3020 Antenna Placement 题解

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

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

然后就可以直接求最小路径覆盖就可以了。
根据公式 无向二分图的最小路径覆盖 \(=\) 顶点数 \(-\) 最大匹配数 \(\div 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 @ 2021-08-24 16:02  jiangtaizhe001  阅读(37)  评论(0编辑  收藏  举报