题解 P1330 【封锁阳光大学】
安利一波自己的博客
蒟蒻不才,写了一发树形dp过了此题。
思路:
首先,我们如果把这个图当做树来看的话,那么它有可能不止一棵树,所以它有可能是森林。我们可以用并查集来维护每一个连通块,设
解决完了遍历的问题后,我们设
然后我们将每一个联通块跑一遍树形
最后需要注意的一个点,如果
#include <bits/stdc++.h>
using namespace std;
struct Node
{
int t;
int next;
}node[200011];
bool book[10011];
int root[10011],f[10011];
int head[10011],tot=0,dp[10011][2];
int n,m;
void init()
{
for(int i=1;i<=n;++i)
f[i]=i,root[i]=i;
}
int getf(int v)
{
if(f[v]==v) return v;
else return f[v]=getf(f[v]);
}
void merge(int a,int b)
{
int t1=getf(a),t2=getf(b);
if(t1!=t2) f[t2]=t1,root[t2]=root[t1];
}
void add(int x,int y)
{
node[++tot].t=y;
node[tot].next=head[x];
head[x]=tot;
}
void dfs(int f,int fa)
{
if(book[f])
{
cout<<"Impossible";
exit(0);
}
book[f]=1;
dp[f][1]=1;
bool flag=0;
for(int i=head[f];i;i=node[i].next)
{
int u=node[i].t;
if(u==fa) continue;
dfs(u,f);
dp[f][0]+=dp[u][1];
dp[f][1]+=dp[u][0];
}
}
int main()
{
// freopen(".in","r",stdin);
// freopen(".out","w",stdout);
int ans=0;
scanf("%d %d",&n,&m);
init();
for(int i=1;i<=m;++i)
{
int x,y;
scanf("%d %d",&x,&y);
merge(x,y);
add(x,y);
add(y,x);
}
if(m>=n)
cout<<"Impossible";
else
{
for(int i=1;i<=n;++i)
if(!book[i])
{
int ta=getf(i);
dfs(root[ta],0);
ans+=min(dp[ta][0],dp[ta][1]);
}
printf("%d",ans);
}
return 0;
}