洛谷P6900 [ICPC2014 WF]Sensor Network 题解
题目链接:P6900 [ICPC2014 WF]Sensor Network
题目大意:给定一个平面,其上有 \(n(n\leq 100)\) 个点,两点之间若欧几里得距离不超过 \(d\) 则有连边,问图上的最大团。
题解:考虑最终答案的点集,我们将其中距离最远的两个点找出来,记两点之间的距离为 \(x\),分别以两点为圆心,\(x\) 为半径做两个圆,则点集内的所有点必然在两圆之内。
考虑根据这个性质来推做法,我们可以枚举原图中距离不超过 \(d\) 的两点作圆,将交点内的点集拉出来暴力建图求最大团(最大团的求法是改成求反图的最大独立集),然后我们发现如果将两个点连一条线,那么集中在这条线上方的点两两之间距离不可能超过 \(d\),下方同理,这样的话图就变成了二分图,然而二分图求最大独立集是可以直接跑网络流的。
枚举点对的时间复杂度是 \(O(n^2)\),二分图最大独立集的时间复杂度是 \(O(m\sqrt{n})=O(n^{2.5})\),总时间复杂度为 \(O(n^{4.5})\),但是肉眼可见地跑不满。
代码:
#include <cstdio>
const int Maxn=100;
const int Maxm=10100;
int n,d;
struct Node{
int x,y;
Node(int _x=0,int _y=0){
x=_x;
y=_y;
}
friend Node operator -(Node a,Node b){
return Node(b.x-a.x,b.y-a.y);
}
friend int operator *(Node a,Node b){
return a.x*b.y-a.y*b.x;
}
}a[Maxn+5];
int lis[Maxn+5],lis_len;
bool bel[Maxn+5];
int id[Maxn+5];
int ans_lis[Maxn+5];
int t_lis[Maxn+5],t_len;
int dis[Maxn+5][Maxn+5];
bool check(Node a,Node b,Node c){
return (c-a)*(b-a)>0;
}
int find_dist(Node a,Node b){
return (b.x-a.x)*(b.x-a.x)+(b.y-a.y)*(b.y-a.y);
}
namespace Dinic{
const int Inf=0x3f3f3f3f;
int min(int a,int b){
return a<b?a:b;
}
struct Edge{
int to,nxt,cap,flow;
}edge[Maxm<<1|5];
bool vis[Maxn+5];
int head[Maxn+5],cur_f[Maxn+5],tot;
void unuse_add_edge(int from,int to,int cap){
edge[++tot].to=to;
edge[tot].nxt=head[from];
edge[tot].cap=cap;
edge[tot].flow=0;
head[from]=tot;
}
void add_edge(int from,int to,int cap){
unuse_add_edge(from,to,cap);
unuse_add_edge(to,from,0);
}
int S,T;
int id_tot;
int qu[Maxn+5],qu_f,qu_t;
int dep[Maxn+5];
int new_node(){
id_tot++;
return id_tot;
}
bool Dinic_bfs(){
for(int i=1;i<=id_tot;i++){
dep[i]=0;
}
dep[S]=1;
qu_f=1,qu_t=0;
qu[++qu_t]=S;
while(qu_f<=qu_t){
int u=qu[qu_f++];
for(int i=head[u];i;i=edge[i].nxt){
int v=edge[i].to;
if(edge[i].flow==edge[i].cap||dep[v]){
continue;
}
dep[v]=dep[u]+1;
qu[++qu_t]=v;
}
}
return dep[T]>0;
}
int Dinic_dfs(int u,int flow){
if(u==T){
return flow;
}
int sum=0;
for(int &i=cur_f[u];i;i=edge[i].nxt){
int v=edge[i].to;
if(dep[v]!=dep[u]+1||edge[i].flow==edge[i].cap){
continue;
}
int op=min(flow-sum,edge[i].cap-edge[i].flow),f;
if((f=Dinic_dfs(v,op))){
sum+=f;
edge[i].flow+=f;
edge[((i-1)^1)+1].flow-=f;
if(sum==flow){
break;
}
}
}
if(sum==0){
dep[u]=0;
}
return sum;
}
int Dinic(){
int ans=0;
while(Dinic_bfs()){
for(int i=1;i<=id_tot;i++){
cur_f[i]=head[i];
}
ans+=Dinic_dfs(S,Inf);
}
return ans;
}
void clear(){
for(int i=1;i<=id_tot;i++){
vis[i]=0;
head[i]=0;
}
id_tot=0;
tot=0;
S=++id_tot;
T=++id_tot;
}
void work_dfs(int u=S){
vis[u]=1;
for(int i=head[u];i;i=edge[i].nxt){
int v=edge[i].to;
if(edge[i].flow<edge[i].cap&&!vis[v]){
work_dfs(v);
}
}
}
}
int main(){
scanf("%d%d",&n,&d);
d*=d;
for(int i=1;i<=n;i++){
scanf("%d%d",&a[i].x,&a[i].y);
}
for(int i=1;i<=n;i++){
for(int j=1;j<=n;j++){
dis[i][j]=find_dist(a[i],a[j]);
}
}
int ans=1;
ans_lis[1]=1;
for(int i=1;i<=n;i++){
for(int j=i+1;j<=n;j++){
if(dis[i][j]>d){
continue;
}
int tmp_d=dis[i][j];
Dinic::clear();
lis_len=0;
t_len=0;
t_lis[++t_len]=i;
t_lis[++t_len]=j;
for(int k=1;k<=n;k++){
if(k==i||k==j){
continue;
}
if(dis[i][k]<=tmp_d&&dis[j][k]<=tmp_d){
lis[++lis_len]=k;
bel[lis_len]=check(a[i],a[j],a[k]);
}
}
for(int k=1;k<=lis_len;k++){
id[k]=Dinic::new_node();
if(bel[k]){
Dinic::add_edge(Dinic::S,id[k],1);
}
else{
Dinic::add_edge(id[k],Dinic::T,1);
}
}
for(int k=1;k<=lis_len;k++){
for(int l=k+1;l<=lis_len;l++){
if(dis[lis[k]][lis[l]]>d){
if(bel[k]){
Dinic::add_edge(id[k],id[l],1);
}
else{
Dinic::add_edge(id[l],id[k],1);
}
}
}
}
Dinic::Dinic();
Dinic::work_dfs();
for(int k=1;k<=lis_len;k++){
if(bel[k]==Dinic::vis[id[k]]){
t_lis[++t_len]=lis[k];
}
}
if(t_len>ans){
ans=t_len;
for(int k=1;k<=t_len;k++){
ans_lis[k]=t_lis[k];
}
}
}
}
printf("%d\n",ans);
for(int i=1;i<=ans;i++){
printf("%d ",ans_lis[i]);
}
puts("");
return 0;
}
本作品采用知识共享署名-非商业性使用-相同方式共享 4.0 国际许可协议进行许可。