• Gym 101221I BZOJ 4080 [WF2014]Sensor Network (二分图匹配)


    题目链接

    (Gym) https://codeforces.com/gym/101221/
    (BZOJ) 大人,时代变了。

    题解

    又是一道看了题解的作业题。
    这是一个最大团(或者补图上的最大独立集)问题,而二分图最大独立集是可以做的,因此可以考虑转化成二分图。
    枚举点集的直径的两端点 (x,y),满足 (dis(x,y)le d),那么剩下点的可选范围就是两个分别以 (x,y) 为圆心、(dis(x,y)) 为半径的圆的交。

    可以发现,以两点连线为界,交的区域被分成了两部分。如果两个点距离大于 (dis(x,y)),那么它们一定位于不同的两部分。
    于是天然的二分图就构建好了!在上面求最大独立集也就是用总点数减去最大匹配即可。
    时间复杂度 (O(n^{4.5})),但是跑得飞快,cf 上只用 (46 ext{ms}).
    另外 lk 的博客上说是 (O(n^4)),但并不知道为什么。

    代码

    #include<bits/stdc++.h>
    #define llong long long
    #define mkpr make_pair
    #define x first
    #define y second
    #define iter iterator
    #define riter reverse_iterator
    #define y1 Lorem_ipsum_
    #define tm dolor_sit_amet_
    using namespace std;
    
    inline int read()
    {
    	int x = 0,f = 1; char ch = getchar();
    	for(;!isdigit(ch);ch=getchar()) {if(ch=='-') f = -1;}
    	for(; isdigit(ch);ch=getchar()) {x = x*10+ch-48;}
    	return x*f;
    }
    
    namespace NetFlow
    {
    	const int N = 202;
    	const int M = 10200;
    	const int INF = 1e6;
    	struct Edge
    	{
    		int v,w,nxt;
    	} e[(M<<1)+3];
    	int fe[N+3];
    	int te[N+3];
    	int dep[N+3];
    	int que[N+3];
    	int n,en,s,t;
    	void clear()
    	{
    		for(int i=1; i<=n; i++) fe[i] = te[i] = dep[i] = que[i] = 0;
    		for(int i=1; i<=en; i++) e[i].v = e[i].w = e[i].nxt = 0;
    		n = s = t = 0; en = 1;
    	}
    	void addedge(int u,int v,int w)
    	{
    //		printf("addedge %d %d %d
    ",u,v,w);
    		en++; e[en].v = v; e[en].w = w;
    		e[en].nxt = fe[u]; fe[u] = en;
    		en++; e[en].v = u; e[en].w = 0;
    		e[en].nxt = fe[v]; fe[v] = en;
    	}
    	bool bfs()
    	{
    		for(int i=1; i<=n; i++) dep[i] = 0;
    		int head = 1,tail = 1; que[1] = s; dep[s] = 1;
    		while(head<=tail)
    		{
    			int u = que[head]; head++;
    			for(int i=fe[u]; i; i=e[i].nxt)
    			{
    				int v = e[i].v;
    				if(e[i].w>0 && dep[v]==0)
    				{
    					dep[v] = dep[u]+1;
    					if(v==t) return true;
    					tail++; que[tail] = v;
    				}
    			}
    		}
    		return false;
    	}
    	int dfs(int u,int cur)
    	{
    		if(u==t||cur==0) {return cur;}
    		int rst = cur;
    		for(int &i=te[u]; i; i=e[i].nxt)
    		{
    			int v = e[i].v;
    			if(e[i].w>0 && rst>0 && dep[v]==dep[u]+1)
    			{
    				int flow = dfs(v,min(rst,e[i].w));
    				if(flow>0)
    				{
    					e[i].w -= flow;	
    					rst -= flow;
    					e[i^1].w += flow;
    					if(rst==0) {return cur;}
    				}
    			}
    		}
    		if(rst==cur) {dep[u] = -2;}
    		return cur-rst;
    	}
    	int dinic(int _n,int _s,int _t)
    	{
    		n = _n,s = _s,t = _t;
    		int ret = 0;
    		while(bfs())
    		{
    			for(int i=1; i<=n; i++) te[i] = fe[i];
    			memcpy(te,fe,sizeof(int)*(n+1));
    			ret += dfs(s,INF);
    		}
    		return ret;
    	}
    	void dfs2(int u)
    	{
    		dep[u] = 1;
    		for(int i=fe[u]; i; i=e[i].nxt) if(e[i].w>0)
    		{
    			int v = e[i].v; if(dep[v]) continue;
    			dfs2(v);
    		}
    	}
    	void calcway()
    	{
    		for(int i=1; i<=n; i++) dep[i] = 0;
    		dfs2(1);
    	}
    }
    using NetFlow::addedge;
    using NetFlow::dinic;
    
    const int mxN = 100;
    struct Point {int x,y;};
    typedef Point Vector;
    Point operator +(Point x,Point y) {return (Point){x.x+y.x,x.y+y.y};}
    Point operator -(Point x,Point y) {return (Point){x.x-y.x,x.y-y.y};}
    int Norm2(Vector x) {return x.x*x.x+x.y*x.y;}
    int Cross(Vector x,Vector y) {return x.x*y.y-x.y*y.x;}
    
    Point a[mxN+3]; vector<int> way;
    int n; int d;
    
    int main()
    {
    	n = read(),d = read();
    	for(int i=1; i<=n; i++) {a[i].x = read(),a[i].y = read();}
    	int ans = 1; way.push_back(1);
    	for(int x=1; x<=n; x++) for(int y=x+1; y<=n; y++) if(Norm2(a[x]-a[y])<=d*d)
    	{
    		vector<int> s1,s2; int cd = Norm2(a[x]-a[y]);
    		for(int i=1; i<=n; i++) if(i!=x&&i!=y&&Norm2(a[i]-a[x])<=cd&&Norm2(a[i]-a[y])<=cd)
    		{
    			if(Cross(a[y]-a[x],a[i]-a[x])>=0) {s1.push_back(i);} else {s2.push_back(i);}
    		}
    		NetFlow::clear();
    		for(int i=0; i<s1.size(); i++) addedge(1,i+3,1);
    		for(int i=0; i<s2.size(); i++) addedge(i+s1.size()+3,2,1);
    		for(int i=0; i<s1.size(); i++) for(int j=0; j<s2.size(); j++)
    		{
    			if(Norm2(a[s2[j]]-a[s1[i]])>cd) {addedge(i+3,j+s1.size()+3,1);}
    		}
    		int cur = s1.size()+s2.size()-dinic(s1.size()+s2.size()+2,1,2)+2;
    		if(cur>ans)
    		{
    			ans = cur; way.clear(); way.push_back(x),way.push_back(y);
    			NetFlow::calcway();
    			for(int i=0; i<s1.size(); i++) if(NetFlow::dep[i+3]) {way.push_back(s1[i]);}
    			for(int i=0; i<s2.size(); i++) if(!NetFlow::dep[i+s1.size()+3]) {way.push_back(s2[i]);}
    		}
    	}
    	printf("%d
    ",ans);
    	for(int i=0; i<way.size(); i++) printf("%d ",way[i]); puts("");
    	return 0;
    }
    
  • 相关阅读:
    VB获取对象成员
    VB一键扫雷
    VBS代码
    C# LINQ GroupBy
    C# 元组和值元组
    数据结构笔记
    DoTween使用
    Unity中常用的数据结构总结
    Unity 坐标系转换
    .Net中C# Dictionary 用法
  • 原文地址:https://www.cnblogs.com/suncongbo/p/14254669.html
Copyright © 2020-2023  润新知