scu 4439 Vertex Cover(暴搜+剪枝)

题目链接

Vertex Cover

frog has a graph with n vertices v(1),v(2),…,v(n) and m edges (v(a1),v(b1)),(v(a2),v(b2)),…,(v(am),v(bm)).

She would like to color some vertices so that each edge has at least one colored vertex.

Find the minimum number of colored vertices.

Input

The input consists of multiple tests. For each test:

The first line contains 2 integers n,m (2≤n≤500,1≤m≤n(n−1)2). Each of the following m lines contains 2 integers ai,bi (1≤ai,bi≤n,ai≠bi,min{ai,bi}≤30)

Output

For each test, write 1 integer which denotes the minimum number of colored vertices.

Sample Input

    3 2
    1 2
    1 3
    6 5
    1 2
    1 3
    1 4
    2 5
    2 6

Sample Output

    1
    2

题意:n个点,m条边的无向图,n<=500,m<=n*(n-1)/2,对于每条边(u,v),min(u,v)<=30。求最少需要多少个点覆盖所有的边。

题解:求一般图的最小顶点覆盖,是NPC问题,所以这题只有搜了。这题的关键点在于min(u,v)<=30。我们可以搜索前30个点的状态,在加上剪枝解决此题。

具体搜索方法如下:

只搜索前30个点的选与不选,如果还有边没有被覆盖则一定选非前30的点来覆盖。这样一定可以搜索到最优解。

如果一个点不选则起相邻的点必选。

所以我们初始化所有的点都选,然后搜索哪些点不选。

当我们搜索到一个点的时候,判断它相邻的点是否有不选的,若有则必选;否则我们可以选择不选该点。这样搜索出来的状态对于前30个点之间的边来说一定是合法的。再加上最优性剪枝就可过这题。

代码如下:

#include<stdio.h>
#include<iostream>
#include<algorithm>
#include<math.h>
#include<string.h>
#include<queue>
#include<list>
using namespace std;
typedef long long LL;
const int nn = 550;
const int inf = 0x3fffffff;
const int mod = 10000003;
int n,m;
struct node
{
    int en,next;
}E[nn*nn*2];
int p[nn],num;
void init()
{
    memset(p,-1,sizeof(p));
    num=0;
}
void add(int st,int en)
{
    E[num].en=en;
    E[num].next=p[st];
    p[st]=num++;

    E[num].en=st;
    E[num].next=p[en];
    p[en]=num++;
}
pair<int,int>a[35];
bool use[35];
bool tu[35][35];
int N;
int ans;
int du[nn];
int fg;
int fuck[nn];
void dfs(int id,int val)
{
    if(val+fg>=ans)
        return ;
    if(id==N+1)
    {
        ans=min(ans,val+fg);
        return ;
    }
    bool ok=true;
    int i,w;
    for(i=1;i<=N;i++)
    {
        if(tu[id][i]&&use[i])
        {
            ok=false;
        }
    }
    if(ok)
    {
        use[id]=true;
        for(i=p[id];i+1;i=E[i].next)
        {
            w=E[i].en;
            if(fuck[w]==0)
            {
                fg++;
            }
            fuck[w]++;
        }
        dfs(id+1,val);
        for(i=p[id];i+1;i=E[i].next)
        {
            w=E[i].en;
            fuck[w]--;
            if(fuck[w]==0)
            {
                fg--;
            }
        }
        use[id]=false;
    }
    dfs(id+1,val+1);
}
int main()
{
    int i,u,v;
    while(scanf("%d%d",&n,&m)!=EOF)
    {
        init();
        memset(tu,false,sizeof(tu));
        memset(fuck,0,sizeof(fuck));
        memset(du,0,sizeof(du));
        for(i=1;i<=m;i++)
        {
            scanf("%d%d",&u,&v);
            if(u>30||v>30)
                add(u,v);
            du[u]++,du[v]++;
            if(u<=30&&v<=30)
                tu[u][v]=tu[v][u]=true;
        }
        fg=0;
        N=min(30,n);
        memset(use,false,sizeof(use));
        ans=m;
        dfs(1,0);
        printf("%d\n",ans);
    }
    return 0;
}

采用Bitset的代码如下:

#include<stdio.h>
#include<iostream>
#include<algorithm>
#include<math.h>
#include<string.h>
#include<queue>
#include<list>
#include<bitset>
using namespace std;
typedef long long LL;
const int nn = 550;
const int inf = 0x3fffffff;
const int mod = 10000003;
bitset<505>be[35];
int n,m;
pair<int,int>a[35];
bool use[35];
bool tu[35][35];
int N;
int ans;
int fg;
bitset<505>bit;
void dfs(int id,int val)
{
    if(val+fg>=ans)
        return ;
    if(id==N+1)
    {
        ans=min(ans,val+fg);
        return ;
    }
    bool ok=true;
    int i;
    for(i=1;i<=N;i++)
    {
        if(tu[id][i]&&use[i])
            ok=false;
    }
    if(ok)
    {
        use[id]=true;
        bitset<505>tem=bit;
        bit|=be[id];
        fg=bit.count();
        dfs(id+1,val);
        bit=tem;
        fg=bit.count();
        use[id]=false;
    }
    dfs(id+1,val+1);
}
int main()
{
    int i,u,v;
    while(scanf("%d%d",&n,&m)!=EOF)
    {
        N=min(30,n);
        for(i=1;i<=N;i++)
        {
            be[i].reset();
        }
        memset(tu,false,sizeof(tu));
        for(i=1;i<=m;i++)
        {
            scanf("%d%d",&u,&v);
            if(u>30)
                be[v].set(u);
            else if(v>30)
                be[u].set(v);
            else
                tu[u][v]=tu[v][u]=true;
        }
        fg=0;
        memset(use,false,sizeof(use));
        ans=m;
        bit.reset();
        dfs(1,0);
        printf("%d\n",ans);
    }
    return 0;
}


  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值