洛谷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;
}
posted @ 2021-03-04 19:28  with_hope  阅读(89)  评论(0编辑  收藏  举报