zoukankan      html  css  js  c++  java
  • Uva LA6450 Social Advertising DFS

    You have decided to start up a new social networking company. Other existing popular social networks
    already have billions of users, so the only way to compete with them is to include novel features no
    other networks have.
    Your company has decided to market to advertisers a cheaper way to charge for advertisements (ads).
    The advertiser chooses which users' wall" the ads would appear on, and only those ads are charged.
    When an ad is posted on a user's wall, all of his/her friends (and of course the user himself/herself )
    will see the ad. In this way, an advertiser only has to pay for a small number of ads to reach many
    more users.
    You would like to post ads to a particular group of users with the minimum cost. You already have
    the friends list" of each of these users, and you want to determine the smallest number of ads you have
    to post in order to reach every user in this group. In this social network, if A is a friend of B, then B
    is also a friend of A for any two users A and B.
    Input
    The input consists of multiple test cases. The rst line of input is a single integer, not more than
    10, indicating the number of test cases to follow. Each case starts with a line containing an integer n
    (1  n  20) indicating the number of users in the group. For the next n lines, the ith line contains the
    friend list of user i (users are labelled 1; : : : ; n). Each line starts with an integer d (0  d < n) followed
    by d labels of the friends. No user is a friend of himself/herself.
    Output
    For each case, display on a line the minimum number of ads needed to be placed in order for them to
    reach the entire group of users.
    Sample Input
    2
    5
    4 2 3 4 5
    4 1 3 4 5
    4 1 2 4 5
    4 1 2 3 5
    4 1 2 3 4
    5
    2 4 5
    2 3 5
    1 2
    2 1 5
    3 1 2 4
    Sample Output
    1
    2

    题意:有个公司做广告,如果在某个人那里做广告,和他相连的朋友都可以知道广告,要求所有的人知道广告,并且做广告的数量最少。

         所以是找最少的点把所有相连的点覆盖。

    思路:枚举任意一种组合当只有一个人时是否可以全部覆盖,如果不行,就枚举任意两个人是否可以全部覆盖,再依次类推,知道找到就break;

         DFS到达叶子节点时才计算是否全部覆盖,这个题很容易超时。后来看看别人是怎么写的,他用了2进制枚举,那样时间复杂度就更高了,

         不过他没有用邻接表,而是用二进制建边,有点6。

       本人代码:

        

    #include <iostream>
    #include <cstdio>
    #include <cstring>
    #include <vector>
    using namespace std;
    
    const int maxn=25;
    int n,flag;
    vector<int> f[maxn];
    int vis[maxn];
    int cnt[maxn];
    
    bool is_ok(int s)
    {
        memset(vis,0,sizeof(vis));
        int i,j,sum=0;
        for(i=0;i<s;i++)
        {
            if(!vis[cnt[i]])
            { 
                vis[cnt[i]]=1;sum++;
            }
            for(j=0;j<f[cnt[i]].size();j++)
            {
                if(!vis[f[cnt[i]][j]])
                {
                    vis[f[cnt[i]][j]]=1;sum++;
                }
            }
        }
        if(sum==n) return 1;
        return 0;
    }
    void dfs(int now,int s,int dep)
    {
        if(now>n+1) return ;
        if(s==dep)
        {
            if(is_ok(s)) flag=1;
            return ;
        }
        cnt[s]=now;
        dfs(now+1,s+1,dep);
        dfs(now+1,s,dep);
    }
    int main()
    {
        int t,i,k,p;
        scanf("%d",&t);
        while(t--)
        {
            scanf("%d",&n);
            for(i=1;i<=n;i++) f[i].clear();
            for(i=1;i<=n;i++)
            {
                scanf("%d",&k);
                while(k--)
                {
                    scanf("%d",&p);
                    f[i].push_back(p);f[p].push_back(i);
                }
            }
            flag=0;
            for(i=1;i<=n;i++)
            {
                dfs(1,0,i);
                if(flag) break;
            }
            printf("%d
    ",i);
        }
        return 0;
    }


    用他的建边代码改进,时间少了100+ms

     改进代码:

         

    #include <iostream>
    #include <cstdio>
    #include <cstring>
    #include <vector>
    using namespace std;
    
    const int maxn=25;
    int n,flag;
    int vis[maxn];
    int cnt[maxn];
    int eg[maxn];
    
    bool is_ok(int s)
    {
        int ans = 0;
        for(int i=0;i<s;i++)
           ans |=eg[cnt[i]];
        if(ans == (1<<n)-1 ) return true;   //所有顶点都访问了
        return false;
    }
    void dfs(int now,int s,int dep)
    {
        if(now>n+1) return ;
        if(s==dep)
        {
            if(is_ok(s)) flag=1;
            return ;
        }
        cnt[s]=now;
        dfs(now+1,s+1,dep);
        dfs(now+1,s,dep);
    }
    
    int main()
    {
        int t,i,k,p;
        scanf("%d",&t);
        while(t--)
        {
            scanf("%d",&n);
            memset(eg,0,sizeof(eg));
            for(i=1;i<=n;i++)
            {
                scanf("%d",&k);
                eg[i] |=1<<(i - 1);
                while(k--)
                {
                    scanf("%d",&p);
                    eg[i] |=1<<(p - 1);     //表示第i条边与第p条边有连边
                }
            }
            flag=0;
            for(i=1;i<=n;i++)
            {
                dfs(1,0,i);
                if(flag) break;
            }
    
            printf("%d
    ",i);
        }
        return 0;
    }
    
    /*
    2
    5
    4 2 3 4 5
    4 1 3 4 5
    4 1 2 4 5
    4 1 2 3 5
    4 1 2 3 4
    5
    2 4 5
    2 3 5
    1 2
    2 1 5
    3 1 2 4
    
      */
  • 相关阅读:
    Java日期工具类,Java时间工具类,Java时间格式化
    js 小数取整,js 小数向上取整,js小数向下取整
    Tomcat v7.0 Server at localhost are already in use,tomcat提示端口被占用,tomcat端口已经被使用,tomcat端口占用
    easyui datebox 时间限制,datebox开始时间限制结束时间,datebox截止日期比起始日期大
    Jquery Easyui验证扩展,Easyui验证,Easyui校验,js正则表达式
    根据日期字符串获取星期几,日期获取星期,时间获取星期,js获取星期
    jquery easyui combobox 级联及触发事件,combobox级联
    js计算2个日期相差的天数,两个日期相差的天数,日期相隔天数
    设置checkbox选中,设置radio选中,根据值设置checkbox选中,checkbox勾选
    layer弹出层不居中解决方案,layer提示不屏幕居中解决方法,layer弹窗不居中解决方案
  • 原文地址:https://www.cnblogs.com/BruceNoOne/p/3886740.html
Copyright © 2011-2022 走看看