这道题,看一眼,感觉很像二分图,感觉既然需要把每条路都覆盖上,那么这个图看似是树,实际上也是一个二分图,举个例子
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;
}