正题
大意
一个n个点n条边的无向图,在一个点安电子眼就能监视到连接它的边,要求所有的边都被监视求安放电子眼的最少数目。
解题思路
就是没一条边的两头都至少得有一个电子眼。我们先假设它是n-1条边的环
用f[i]f[i]来表示不在这个点放电子眼的最少电子眼数目
用g[i]g[i]来表示在这个点放电子眼的最少电子眼数目
然后我们可以进行推算,一个点不放电子眼,那么它的子节点就一点要放。
f[i]=g[son]f[i]=g[son]
如果一个地方放电子眼,那么它的子节点就可放可不放
g[i]=max{f[son],g[son]}g[i]=max{f[son],g[son]}
然后我们在处理环。发现环时我们可以不去进行dp该点但是取该点的结果。
代码
#include<cstdio>
#include<algorithm>
#include<cstring>
using namespace std;
struct node{int to,next;
}a[200001];
int ls[100001],g[100001],f[100001],tot,n,k,x,maxs;
bool v[100001];
void addl(int x,int y)
{a[++tot].to=y;a[tot].next=ls[x];ls[x]=tot;
}
void dp(int x)
{int s1=1,s2=0;for (int i=ls[x];i;i=a[i].next){if (!v[a[i].to]){v[a[i].to]=1;//标记dp(a[i].to);//dps1+=min(g[a[i].to],f[a[i].to]);//动态转移}s2+=g[a[i].to];//处理环(因为父节点没有值所以不会有影响)}g[x]=s1;f[x]=s2;//保证搜完子节点之前父节点没有值
}
int main()
{scanf("%d",&n);for (int i=1;i<=n;i++){scanf("%d",&k);for (int j=1;j<=k;j++)scanf("%d",&x),addl(i,x);}v[1]=1; dp(1);printf("%d",min(f[1],g[1]));//输出
}