题意:
给出n个点的坐标,从中选几个点,要求任意两个点之间的距离不能小于1.3(因为坐标都是整数,两点之间距离为1或者1.414或者更大,则要求大于1即可)。
题解:
理论基础:最大独立集 = 点的个数(n)- 最大匹配,这里的最大匹配是指两点距离为1的最大匹配。
那么只要求出反向的最大匹配就ok了。
求最大匹配肯定要用到基于二分图的匈牙利算法,既然基于二分图,那么必须把这n个点分成两部分,如何分是个问题。
我们要求每一部分的任意两点距离都得大于1,这里有个小技巧【按照x+y的值,分成奇数和偶数两部分,若两个点x+y奇偶性相同,那么这两点距离一定是大于1的】
附代码:
#include <set> #include <map> #include <cmath> #include <stack> #include <queue> #include <vector> #include <string> #include <cstdio> #include <cstring> #include <sstream> #include <iomanip> #include <iostream> #include <algorithm> #define clr(str,x) memset(str,x,sizeof(str)) #define FRER() freopen("in.txt","r",stdin); #define FREW() freopen("out.txt","w",stdout); #define INF 0x7fffffff #define maxn 2010 typedef long long int ll; using namespace std; struct node { int x; int y; } nodes[maxn]; bool cmp(node a,node b) { return a.x+a.y<b.x+b.y; } vector<int> edg[maxn]; bool vis[maxn]; int match[maxn]; bool Find(int x) { for(int i=0; i<edg[x].size(); i++) { int j=edg[x][i]; if(vis[j]==false) { vis[j]=true; if(match[j]==-1||Find(match[j])) { match[j]=x; return true; } } } return false; } int main() { //FRER() //FREW() int n; while(scanf("%d",&n)!=EOF) { for(int i=1; i<=n; i++) { edg[i].clear(); scanf("%d%d",&nodes[i].x,&nodes[i].y); } sort(nodes+1,nodes+1+n,cmp); for(int i=1; i<=n; i++) { for(int j=1; j<=n; j++) { if((nodes[i].x-nodes[j].x)*(nodes[i].x-nodes[j].x)+(nodes[i].y-nodes[j].y)*(nodes[i].y-nodes[j].y)==1) { edg[i].push_back(j); edg[j].push_back(i); } } } memset(vis,false,sizeof(vis)); memset(match,-1,sizeof(match)); int num=0; for(int i=1; i<=n; i++) { if((nodes[i].x+nodes[i].y)&1) { memset(vis,false,sizeof(vis)); if(Find(i)) num++; } } printf("%d\n",n-num); } return 0; }