hdu 1054 Strategic Game 树上的点覆盖集

题目即求树上的点覆盖数。

对于一个图的点覆盖集,都不存在多项式内的解法,但如果是树的话,却挺容易,有三种方法,第一个是贪心,第二个是树形dp,第三个是二分图匹配(树是一个二分图),我是用贪心做的,先深度优先遍历一遍得到遍历序列,将遍历序列反向(即后序遍历序列)进行贪心,这样可以保证对于每个节点来说,当其子树都被处理过后才轮到该节点,保证了贪心的正确性,贪心思路为:若当前点和当前点的父节点都不属于点覆盖集,则将当前节点的父节点加入到点覆盖集,并标记当前节点和其父节点都被覆盖。

#include <stdio.h>
#include <vector>
using namespace std;
#define maxn 1600
vector <int> g[maxn];
int now,n,m,p[maxn],newpos[maxn],vis[maxn];
void dfs(int u)
{
    newpos[now++]=u;
    int i,t;
    for(i=0;i<g[u].size();i++)
    {
        t=g[u][i];
        if(vis[t]) continue;
        vis[t]=1;
        p[t]=u;
        dfs(t);
    }
}

int greedy()
{
    bool s[maxn]={0}; 
    bool set[maxn]={0};
    int ans=0;
    int i;
    for(i=n-1;i>=1;i--)
    {
        int t=newpos[i];
        if(!s[t]&&!s[p[t]])
        {
            set[p[t]]=true;
            ans++;
            s[t]=true;
            s[p[t]]=true;
        }
    }
    return ans;
}    

int main()
{
    int i,j;
    int x,y;
    while(scanf("%d",&n)!=EOF)
    {
        memset(p,0,sizeof(p));
        memset(g,0,sizeof(g));
        memset(vis,0,sizeof(vis));
        now=0;
        vis[0]=1;
        for(i=1;i<=n;i++)
        {
            scanf("%d:(%d)",&x,&m);
            for(j=0;j<m;j++)
            {
                scanf("%d",&y);
                g[x].push_back(y);
                g[y].push_back(x);
            }
        }
        dfs(0);
        printf("%d
",greedy());
    }
    return 0;
}

再粘一份匹配的代码,来自http://gzhu-101majia.iteye.com/blog/1157335

#include <iostream>
#include <stdio.h>
#include <memory.h>
#include <vector>
using namespace std;

const int N = 1505;

int pre[N];
bool flag[N];
vector<int> map[N];
int n;

int find(int cur)
{
    int i, k;
    for(i = 0; i < map[cur].size(); i++)
    {
        k = map[cur][i];
        if(!flag[k])
        {
            flag[k] = true;
            if(pre[k] == -1 || find(pre[k]))
            {
                pre[k] = cur;
                return 1;
            }
        }
    }
    return 0;
}

int main()
{
    int i, j, r, k, num, sum;
    while(scanf("%d", &n) != EOF)
    {
        memset(pre, -1, sizeof(pre));
        for(i = 0; i < n; i++) map[i].clear();
        for(i = 0; i < n; i++)
        {
            scanf("%d:(%d)", &k, &num);
            for(j = 0; j < num; j++)
            {
                scanf("%d", &r);
                map[k].push_back(r);	//用邻接表
                map[r].push_back(k);	//建双向图
            }
        }
        sum = 0;
        for(i = 0; i < n; i++)
        {
            memset(flag, false, sizeof(flag));
            sum += find(i);
        }
        printf("%d
", sum/2);
    }

    return 0;
}



 

原文地址:https://www.cnblogs.com/vermouth/p/3710191.html