【BZOJ 3037】 创世纪 树形DP
2016-04-08 10:48
351 查看
树的最小支配集:从v中取尽量少的点组成一个集合,使得对于v中剩余的点都与取出来的点有边相连。
怎么求?
如果是正常的树(无向)的话对于每个节点就是三种状态:
0.这个点被选
1.这个点被父亲节点覆盖
2.这个点被儿子节点覆盖
的最小支配集。
对于这道题呢,建反图后变成外向基环树林,所以对于状态就少了一维(没有状态2),还要在环上随便找一个点将环拆开,然后在枚举这个点选不选,若这个点为x,指向的点为y,则:
1.选x,则f[y][1]=0;
2.不选x,正常做最小支配集即可。
最后就是要注意有向图的找环阿 dfs阿和无向图的区别阿!!!
怎么求?
如果是正常的树(无向)的话对于每个节点就是三种状态:
0.这个点被选
1.这个点被父亲节点覆盖
2.这个点被儿子节点覆盖
的最小支配集。
对于这道题呢,建反图后变成外向基环树林,所以对于状态就少了一维(没有状态2),还要在环上随便找一个点将环拆开,然后在枚举这个点选不选,若这个点为x,指向的点为y,则:
1.选x,则f[y][1]=0;
2.不选x,正常做最小支配集即可。
最后就是要注意有向图的找环阿 dfs阿和无向图的区别阿!!!
#include<cstdio> #include<cstring> #include<iostream> #include<algorithm> #include<vector> using namespace std; const int inf=0x3f3f3f3f; const int N=1000011; int fa ,g ,f ,in ; int head ,next[N*2],key[N*2],tot,vis ; int n,p; void add(int x,int y) { tot++; next[tot]=head[x]; head[x]=tot; key[tot]=y; } void DFS(int x) { vis[x]=1; if(vis[fa[x]]) p=x; else DFS(fa[x]); } void dfs(int x,int fg,int root) { if(x==fg)g[x]=0,f[x]=1; else g[x]=inf,f[x]=1; vis[x]=1; for(int i=head[x];i;i=next[i]) { int y=key[i]; if(y!=root) { dfs(y,fg,root); g[x]+=min(g[y],f[y]); g[x]=min(g[x],f[x]+f[y]-1);//枚举有哪一个儿子选了 或哪些儿子选了 f[x]+=min(f[y],g[y]); } } } int main() { cin>>n; for(int i=1;i<=n;i++) { scanf("%d",&fa[i]);//建反向图 add(fa[i],i); } int ans=0; for(int i=1;i<=n;i++) if(vis[i]==0) { DFS(i);int x=p; int y=fa[x]; if(x) { int tmp=inf; dfs(x,y,x);//强行选x这个点 tmp=min(tmp,f[x]); dfs(x,-1,x);//不选x tmp=min(tmp,g[x]); ans+=tmp; } } printf("%d",n-ans); }
相关文章推荐
- C盘不能新建文件的问题解决办法
- Oracle数据库常用技术
- MPlayer-2016-bin-noConsole
- 可行性分析报告
- CentOS 6.6升级GCC
- interactivePopGestureRecognizer返回时消息传递
- HashMap源码注解 之 常量定义(一)
- App应用之启动界面SplashActivity
- C++一次实验
- Sencha Touch下拉刷新、上拉自动加载
- Android中applicationId与package name的区别
- STL迭代器------Traits编程技法详细理解(一)
- Linux ps --显示当前正在运行的进程列表 2013年7月4日
- ABAP常用函数
- (好)C++ 对象的内存布局(下)
- RecyclerView
- 栈与队列
- Altium designer 覆铜与走线直接相连
- 虚拟机的MAC地址分配与修改
- vs 15 key