洛谷P2016

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/qq_40924940/article/details/85002917

这道题,看一眼,感觉很像二分图,感觉既然需要把每条路都覆盖上,那么这个图看似是树,实际上也是一个二分图,举个例子

A -----  B  ----- C

要想把这个图里的路覆盖上,只需要一个B点就足够了。

而复杂一点的话

A---B---C---D---E

这样的话还是只需要两个点就可以覆盖完全了,那么很显然,对于每个树如果想把所有路径都覆盖上,就可以完全认为这个树的相邻节点都要染上不同颜色,而染上不同颜色之后,我们就能得到了一个二分图了,然后我们换个角度去想,这个图毕竟还是一颗树,而划分成二分图之后,只要理论上一个点有人,和他所连接的所有点之间的路就都可以被看到了,那么这样想,跑一下最大二分图匹配不就好了吗,因为一旦一个点匹配上了邻近的点,说明和他相连的边都不需要再来额外的人观察了,当然因为本题是一个无向图,如果算出最大匹配还需要除以2。

可能有点抽象,虽然是奔着练习树形dp去的,但是看了看题解,发现这种方法貌似真的可行。。

然后叫了一发。。A了。。之后再去看一下树形dp解法。。

以下是二分图最大匹配AC代码

#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
const int maxn = 1e6+5;
struct node
{
	int to,nxt;
}ed[maxn];
int head[maxn],tot;
void add(int u,int v)
{
	ed[++tot].to = v;
	ed[tot].nxt = head[u];
	head[u] = tot;
}
int vis[maxn],lin[maxn];
bool dfs(int s)
{
	for(int i=head[s];~i;i=ed[i].nxt)
	{
		int to = ed[i].to;
		if(!vis[to])
		{
			vis[to] = 1;
			if(lin[to] == -1 || dfs(lin[to]))
			{
				lin[to] = s;
				return true;
			}
		}
	}
	return false;
}
int main()
{
	int n;
	while(~scanf("%d",&n))
	{
		memset(head,-1,sizeof head);
		tot = 0;
		memset(lin,-1,sizeof lin);
		for(int i=1;i<=n;i++)
		{
			int x,y,t;
			scanf("%d%d",&x,&t);
			while(t--)
			{
				scanf("%d",&y);
				add(x+1,y+1);
				add(y+1,x+1);
			}
		}
		int ans = 0;
		for(int i=1;i<=n;i++)
		{
			memset(vis,0,sizeof vis);
			if(dfs(i))
			ans ++;
		}
		printf("%d\n",ans/2);
	}
	return 0;
}

猜你喜欢

转载自blog.csdn.net/qq_40924940/article/details/85002917