1. 程式人生 > >scu 4439 Vertex Cover(暴搜+剪枝)

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;
}