zoukankan      html  css  js  c++  java
  • 洛谷P6900 [ICPC2014 WF]Sensor Network 题解

    题目链接:P6900 [ICPC2014 WF]Sensor Network

    题目大意:给定一个平面,其上有 (n(nleq 100)) 个点,两点之间若欧几里得距离不超过 (d) 则有连边,问图上的最大团。


    题解:考虑最终答案的点集,我们将其中距离最远的两个点找出来,记两点之间的距离为 (x),分别以两点为圆心,(x) 为半径做两个圆,则点集内的所有点必然在两圆之内。

    考虑根据这个性质来推做法,我们可以枚举原图中距离不超过 (d) 的两点作圆,将交点内的点集拉出来暴力建图求最大团(最大团的求法是改成求反图的最大独立集),然后我们发现如果将两个点连一条线,那么集中在这条线上方的点两两之间距离不可能超过 (d),下方同理,这样的话图就变成了二分图,然而二分图求最大独立集是可以直接跑网络流的。

    枚举点对的时间复杂度是 (O(n^2)),二分图最大独立集的时间复杂度是 (O(msqrt{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
    ",ans);
    	for(int i=1;i<=ans;i++){
    		printf("%d ",ans_lis[i]);
    	}
    	puts("");
    	return 0;
    }
    
  • 相关阅读:
    wpf图片查看器,支持鼠标滚动缩放拖拽
    Python 3.x 学习笔记--杂
    Python 3.x 模块
    python 连接kafka
    Oracle问题
    Device Mapper Multipath(DM-Multipath)
    各种书籍
    Centos 6.x系统
    老男孩Python 3.x 讲义
    Python 3.x 学习笔记
  • 原文地址:https://www.cnblogs.com/withhope/p/14482506.html
Copyright © 2011-2022 走看看