zoukankan      html  css  js  c++  java
  • 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;
    }
    



     

  • 相关阅读:
    【Xshell】基本使用-连接远程服务器 | 传输文件
    【Shell】在windows10环境下安装xshell-绿色破解版(解压后,直接使用)
    【windows10】由于找不到msvcr100.dll,无法继续执行代码
    英语单词正音
    汉字正音
    怎样快速阅读一本书
    “做教练”之好声音训练
    “做教练”之硬笔书法
    2017-2018-1学期《程序设计与数据结构》教学进程
    Java Collections 源码分析
  • 原文地址:https://www.cnblogs.com/vermouth/p/3710191.html
Copyright © 2011-2022 走看看