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\n",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\n",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

  */

Uva LA6450 Social Advertising DFS

时间: 2025-01-02 18:52:58

Uva LA6450 Social Advertising DFS的相关文章

LA 6450 social advertising(dfs剪枝)

6450 Social AdvertisingYou have decided to start up a new social networking company. Other existing popular social networksalready have billions of users, so the only way to compete with them is to include novel features noother networks have.Your co

UVa 572 Oil Deposits(DFS)

 Oil Deposits  The GeoSurvComp geologic survey company is responsible for detecting underground oil deposits. GeoSurvComp works with one large rectangular region of land at a time, and creates a grid that divides the land into numerous square plots.

UVA 10318 - Security Panel dfs 剪枝

UVA 10318 - Security Panel dfs 剪枝 ACM 题目地址:UVA 10318 - Security Panel 题意: 这题跟点灯的题目很像,点灯游戏选择一盏灯时会让它以及四周的灯改变状态. 但是我们有特殊的开开关技巧,它给出了改变状态的位置,而不是四周都改变. 问你从全部关着变成全部开着的最小开关步骤. 分析: 很明显,在一个位置上点两次或更多次是没有必要的,所以一个位置只有选择与不选择,用dfs即可,但如果暴力所有可能,复杂度是2^25,会超时,所以要剪枝. 由于

uva 12253 - Simple Encryption(dfs)

题目链接:uva 12253 - Simple Encryption 题目大意:给定K1,求一个12位的K2,使得KK21=K2%1012 解题思路:按位枚举,不且借用用快速幂取模判断结果. #include <cstdio> #include <cstring> #include <algorithm> using namespace std; typedef long long ll; const ll ite=(1<<20)-1; ll N; /* l

UVa 208 消防车(dfs+剪枝)

https://uva.onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&page=show_problem&problem=144 题意:给出一个n个结点的无向图以及某个结点k,按照字典序从小到大顺序输出从1到结点k的所有路径. 思路:如果直接矩阵深搜的话是会超时的,所以我们可以从终点出发,将与终点相连的连通块保存起来,这样dfs深搜时可以剪枝掉一些到达不了的点.只要解决了这个,dfs就是小问题. 这道题还有点坑的

UVA 1103 Ancient Messages (DFS)

起初学习dfs的时候 看不懂这个题目  回过头来今天看的时候思路相对比较清晰了.但还是想不到怎么处理 查询有多少个空白洞.并且一个图中还有好多个象形字符.网上思路是 在周围扩展一圈0,使得文字之外的所有0 都连通,一次dfs标记所有文字之外的0为-1.然后遍历图,发现1就沿着有1 的路径dfs2,在这个过程中,如果发现0,那么必然是文字内部的空洞,此时把空洞dfs 置为-1,标记以后不再走.那么发现几次0就有几个空洞在文字中.那么每一次的dfs2,就处理了一个象形文字.cnt的值就是空洞的个数即

UVA - 1103Ancient Messages(dfs)

UVA - 1103Ancient Messages In order to understand early civilizations, archaeologists often study texts written in ancient languages.One such language, used in Egypt more than 3000 years ago, is based on characters called hieroglyphs.Figure C.1 shows

UVa 572 油田(DFS求连通块)

https://uva.onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&page=show_problem&problem=513 终于开始接触图了,恩,开始接触DFS了,这道题就是求连通分量,比较简单. 1 #include<iostream> 2 #include<cstring> 3 using namespace std; 4 5 int m, n; //记录连通块的数量 6 cha

uva 11218 KTV(DFS+回溯)

uva 11218 KTV One song is extremely popular recently, so you and your friends decided to sing it in KTV. The song has 3 characters, so exactly 3 people should sing together each time (yes, there are 3 microphones in the room). There are exactly 9 peo