题解 CF85E 【Guard Towers】
算法分析:二分答案+二分图判定
首先分析题目大意。很显然,按照题意将塔分为两组后,同组内没有其他联系,于是我们可以想到二分图基本模型。题设的条件就是要求我们将若干座塔构造成一个二分图。于是将题意简化如下:
求一张二分图,使得每组内两个点之间的曼哈顿距离的最大值最小,并求出符合条件的方案数。
等等,我们应该如何建图?注意到最大值最小,可以尝试用二分答案的方式求解。对答案(曼哈顿距离的最大值的最小值)进行二分,在符合距离的两点间连边,然后采用染色法判定该图是不是二分图,如果是,就记录答案,这样一轮结束后,我们就可以得到第一问的答案。
接下来我们解决第二问。如何求方案数?我们先考虑最普通的二分图,其左部点和右部点可以确定。从样例一可以知道,左部和右部可以互换,因此在这种情况下,一共有两种情况。我们再看下图,下图显然是一个可行的二分图,但是有多个连通块,对于每个连通块都有两种方案,因为连通块内部的左部点和右部点互换对其他连通块并没有影响。记连通块数量为 \(k\) ,那么总方案数就有 \(2^k\) 种,由于 \(k\) 可能较大,用快速幂会比较方便。
细节提示:
注意到 \(n\le 5000\),在极限情况下时空复杂度达到\(n^2\) 级别,尽管可以勉强承受,但是过于浪费,因此不必显式建图,可以在染色的同时寻找符合要求的对象。
上代码:
#include<bits/stdc++.h>
#define F(i,a,b) for(register int i=(a);i<=(b);i++)
using namespace std;
const int N=5005,mod=1e9+7;
int n,col[N],num,ans,cnt;
struct P {
int x,y;
} a[N];
inline int dis(P a,P b) {//曼哈顿距离
return abs(a.x-b.x)+abs(a.y-b.y);
}
long long fc(int x,int y) {//快速幂
if(!y)return 1;
long long pos=fc(x,y>>1)%mod;
if(y&1)return pos*pos%mod*x%mod;
return pos*pos%mod;
}
bool dfs(int x,int mi) {
F(i,1,n){
if(dis(a[x],a[i])<=mi or i==x)continue;
if(!col[i]) {
col[i]=col[x]^1;//染色
if(!dfs(i,mi))return false;//染色失败,不是二分图
} else if(col[i]==col[x])return false;//同上
}
return true;
}
inline bool check(int mid) {
memset(col,0,sizeof(col));//记录颜色
num=0;
F(i,1,n) {
if(!col[i]) {
col[i]=2;
num++;//一次dfs出的显然是一个连通块,num记录连通块数量
if(!dfs(i,mid))return false;
}
}
cnt=num;//cnt记录答案的连通块数量
return true;
}
int main() {
scanf("%d",&n);
F(i,1,n)scanf("%d%d",&a[i].x,&a[i].y);
int l=0,r=1e4;
while(l<=r) {//二分答案
int mid=l+r>>1;
check(mid)?r=mid-1,ans=mid:l=mid+1;
}
printf("%d\n%lld\n",ans,fc(2,cnt));
return 0;
}
欢迎交流讨论,请点个赞哦~
本文来自博客园,作者:Maplisky,转载请注明原文链接:https://www.cnblogs.com/lbh2021/p/14922341.html