题目链接
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.
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)
For each test, write 1 integer which denotes the minimum number of colored vertices.
3 2
1 2
1 3
6 5
1 2
1 3
1 4
2 5
2 6
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
#include
#include
#include
#include
#include
#include
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++;
}
paira[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;
}
#include
#include
#include
#include
#include
#include
#include
#include
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;
paira[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;
}