E - Strategic Game (HDU - 1054 )(最小顶点覆盖)(匈牙利算法模板)(树形DP)

题意:鲍勃喜欢玩电脑游戏,特别是战略游戏,但有时他无法找到解决方案,速度不够快,那么他很伤心。现在,他有以下的问题。他必须捍卫一个中世纪的城市,形成了树的道路。他把战士的最低数量的节点上,使他们可以观察所有的边。你能帮助他吗?士兵,鲍勃把一个给定的树,你的程序应该发现的最小数目。输入文件包含多个数据集的文本格式。

我们来先了解一下什么是最小顶点覆盖;

 

G顶点覆盖是一个顶点集合V,使得G中的每一条边都接触V中的至少一个顶点。我们称集合V覆盖了G的边。最小顶点覆盖是用最少的顶点来覆盖所有的边。顶点覆盖数是最小顶点覆盖的大小。

相应地,图G边覆盖是一个边集合E,使得G中的每一个顶点都接触E中的至少一条边。

如果只说覆盖,则通常是指顶点覆盖,而不是边覆盖。

 

由König定理定理可知,二分图的最小顶点覆盖数等于二分图的最大匹配数。

关于König定理的证明网上也比较多。大家可以百度找一找。题目中的这棵树之所以可以当成二分图,是因为如果从一个点出发,那么可以将整棵树分成奇数点层和偶数点层。由于树是一种特殊的图。n个点由(n-1)条边连接起来。这样假定一个点为树的根,假设各点间的边权值为1。那么从树根出发遍历整棵树,根据各点到根的路径的奇偶性即可将所有点分成两个集合。奇数点与偶数点交替出现。假设奇数点与偶数点连边,偶数点则继续和下一层的奇数点连边。这就与二分图中同类集合点间无边,不同类集合点间有边相连吻合起来了。所以满足二分图的性质。也可以用二分图最大匹配进行求解。

由于对该二分图进行了补全(无向图),边增加为原来边的二倍。所以最终结果要除以2。

 二分图最小顶点覆盖=双向二分图最大匹配/2

因为如果不补全的话会因为无法确定边的方向而使得答案错误

 

#include
using namespace std;
const int N=1500+5;

vector G[N];
int visit[N];
int match[N];
int n;
int Find(int u)//匈牙利算法
{
    for(int i=0;i


匈牙利算法模板

 

 

 

有个讲解不错的网址 http://blog.csdn.net/dark_scope/article/details/8880547/

bool find(int x){  
    int i,j;  
    for (j=1;j<=m;j++){    //扫描每个妹子  
        if (line[x][j]==true && used[j]==false)        
        //如果有暧昧并且还没有标记过(这里标记的意思是这次查找曾试图改变过该妹子的归属问题,但是没有成功,所以就不用瞎费工夫了)  
        {  
            used[j]=1;  
            if (girl[j]==0 || find(girl[j])) {   
                //名花无主或者能腾出个位置来,这里使用递归  
                girl[j]=x;  
                return true;  
            }  
        }  
    }  
    return false;  
}  
for (i=1;i<=n;i++)  
{  
    memset(used,0,sizeof(used));    //这个在每一步中清空  
    if find(i) all+=1;  
}  

 

另外也可以用树形DP来做,

 

【状态】:


dp[i][0] 为以 i 为根节点,并且该节点不放,所需要的最少的点数


dp[i][1] 为以 i 为根节点,并且该节点放,所需要的最少的点数

【转移方程】:


dp[i][0]=sum(dp[son[i][j]][1]) 该点不放的话,那么它的儿子节点必须都放,这样之间的边才可以被覆盖


dp[i][1]=sum(min(dp[son[i][j]][0],dp[son[i][j]][1])) 该点放的话,那么它的儿子节点就有两种决策,一种是放,一种是不放,取 min 就行了

 

#include
using namespace std;
const int N=1505;

int dp[N][2],f[N];
int son[N][N],Size[N];
int n;

int dfs(int pos ,int val)
{
    if(dp[pos][val]!=INT_MIN)
        return dp[pos][val];
    int sum= val;
    for(int i=0; i

 

 

 

 

 

 

你可能感兴趣的:(姗姗杯,算法)