[LGOJ]P3033 [USACO11NOV]Cow Steeplechase G

算法标签:二分图最大独立集

二分图各种类型题目数不胜数,这一题便是一个二分图的最大独立集问题

前置芝士

先简短介绍一下匈牙利算法

其实匈牙利算法就是一个妥协的过程,即若一点 A A A于另一点 B B B相连,而该边已有匹配 C C C,则尽可能的让 C C C去寻求其他点进行匹配,然后让 A , B A,B A,B完成匹配(不太地道的感觉

核心代码:

inline bool dfs(int x)
{
	for (int i=head[x];i;i=edge[i].next)
	{
		int y=edge[i].to;
		if (vis[y]==false)
		{
			vis[y]=true;
			if (match[y]==0||dfs(match[y])==true)
			{
				match[y]=x;
				return true;
			}
		}
	}
}

二分图最大独立集

定义
对于一张无向图 G ( V , E ) G(V,E) G(V,E),选出一个 V V V的子集 S S S,使得 S S S任意两点之间都没有边,且 S S S是最大这样的子集。

求解方法:
二分图的最大独立集的点的数量=总点数N-最大匹配而最大匹配用匈牙利即可求得

简单的证明:要使得独立集越大,那么删掉的点就要越少,同时话要保证删掉的点覆盖到所有边,所以删掉的因该是最小点覆盖。

推荐题目:

  • Example1.[LGOJ] P5030长脖子鹿防置
  • Example2.[LGOJ]P3355 骑士共存问题

好的,那么介绍完最大独立集,讲回我们这道题

这题是一个非常典型的二分图最大独立集问题,发现每两条均均是不重合的,于是想到直接将相交的两条线段连接,得到的一点是一个二分图(同边的(即同方向)没有边相连,符合二分图定义)

于是呢我们发现题目所求是"选出尽量多的线段使得这些线段两两没有交点",那么在二分图中间也就是选出尽量多的点使得他们之间没有连边,通过这个建模,我们就将这个题完美地转化成了一个裸的二分图最大独立集问题了,根据

二分图最大独立集=点的个数 − - 最大匹配于是乎这题就可以求解了

最后再讲一下怎么判断相交的问题

  • 判断线段方向即看横纵做坐标哪个相等即可,若 X 1 = X 2 X1=X2 X1=X2则方向为竖,若 Y 1 = Y 2 Y1=Y2 Y1=Y2则为横
  • 对每个坐标进行排序,于是我们得到:
inline bool intersect(node2 x,node2 y)	//x为竖边,y为横边,且横纵坐标均为从小到大
{
	if (x.a.x>=y.a.x&&x.a.x<=y.b.x&&x.a.y<=y.a.y&&x.a.y>=y.b.y)
	{
		return 1;
	}
	return 0;
}

即竖边的 x x x坐标位于横边的两个端点的 x x x坐标之间并且横边的 y y y坐标位于竖边的两个端点的 y y y坐标之间

ok,于是我们便愉快地得到了代码:

#include
using namespace std;
const int maxn=1000005;
int n,cnt,tot,ans;
int head[maxn],vis[maxn],match[maxn];
struct node
{
	int x,y;
};
struct node2
{
	int dir;
	node a,b;
}seg[maxn];
struct node3
{
	int from,to,next;
}edge[maxn];
inline int add(int x,int y)
{
	edge[++tot].next=head[x];
	edge[tot].from=x;
	edge[tot].to=y;
	head[x]=tot;
}
inline int read()
{
	int s=0,f=1;
	char c=getchar();
	while (c<'0'||c>'9')
	{
		if (c=='-')
		{
			f=-1;
		}
		c=getchar();
	}
	while (c>='0'&&c<='9')
	{
		s=s*10+c-48;
		c=getchar();
	}
	return s*f;
}
inline bool cmp(node2 x,node2 y)
{
	return x.dir=y.a.x&&x.a.x<=y.b.x&&y.a.y>=x.a.y&&y.a.y<=x.b.y)
	{
		return 1;
	}
	return 0;
}
inline bool dfs(int x)
{
	for (int i=head[x];i;i=edge[i].next)
	{
		int y=edge[i].to;
		if (vis[y]==false)
		{
			vis[y]=true;
			if (match[y]==0||dfs(match[y])==true)
			{
				match[y]=x;
				return true;
			}
		}
	}
}
int main()
{
	ios::sync_with_stdio(false);
	n=read();
	for (int i=1;i<=n;i++)
	{
		seg[i].a.x=read();
		seg[i].a.y=read();
		seg[i].b.x=read();
		seg[i].b.y=read();
		if (seg[i].a.x==seg[i].b.x)
        {
			seg[i].dir=1;
			cnt++;
			if (seg[i].a.y>seg[i].b.y)
			{
				swap(seg[i].a.y,seg[i].b.y);
			}
        }
        if (seg[i].a.y==seg[i].b.y)
        {
            seg[i].dir=2;
            if (seg[i].a.x>seg[i].b.x)
			{
				swap(seg[i].a.x,seg[i].b.x);
			}
        }
	}
	sort(seg+1,seg+n+1,cmp);
	for (int i=1;i<=cnt;i++)
	{
		for (int j=cnt+1;j<=n;j++)
		{
			if (intersect(seg[i],seg[j]))
			{
				add(i,j);
			}
		}
	}
	for (int i=1;i<=cnt;i++)
	{
		memset(vis,0,sizeof(vis));
		if (dfs(i))
		{
			ans++;
		}
	}
	cout<

你可能感兴趣的:([LGOJ]P3033 [USACO11NOV]Cow Steeplechase G)