最小权顶点覆盖问题

问题描述:

  给定一个赋权无向图G=(V,E),每个顶点v∈V都有一个权值w(v)。如果U包含于V,且对于(u,v)∈E 有u∈U 且v∈V-U,则有v∈K.如:U = {1}, 若有边(1,2), 则有2属于K. 若有集合U包含于V使得U + K = V,就称U 为图G 的一个顶点覆盖。G 的最小权顶点覆盖是指G 中所含顶点权之和最小的顶点覆盖。

算法设计:

  a. 给定的图G 有n 个顶点和m条边,用w[i]存储顶点i的权值,用e[i][j]标记两顶

  点为i和j的边是否存在,用c[i]标记顶点i是否在顶点覆盖集中;

  b. 用函数cover()判断图G 是否被顶点覆盖(用t标记):

  ① 初始t=0;

  ② 采用while循环对每个顶点i(1≤i≤n)进行讨论:

     1> 若顶点i不在顶点覆盖集中(即c[i]==0),则查找与之有边连接的顶点j(即e[i][j]==1),判断所有顶点j:

  若存在顶点j在顶点覆盖集中(即c[j]==0),则t=1;

  若所有顶点j都不在顶点覆盖集中(即t==0),则图G 未被顶点

  覆盖(return 0);

  2> 当i>n时循环结束;

  ③ return 1;

  c. 用递归函数cut(i, s) 来实现回溯法搜索子集树(形式参数i表示递归深度,n用

  来控制递归深度,形式参数s表示当前顶点权之和):  

  ① 若s>=bestw,则不是最优解,剪去相应子树,返回到i-1层继续执行;

  ② 若i >n,则算法搜索到一个叶结点,调用函数cover()对图G进行判断:

  若cover()为真,则用bestw对最优解进行记录,返回到i-1层继续执行;

  ③ 对顶点i分在与不在顶点覆盖集中两种情况进行讨论:

  1> 若顶点i不在顶点覆盖集中(即c[i]==0),则调用函数cut(i+1,s);

  2> 若顶点i在顶点覆盖集中(即c[i]==1),则调用函数cut(i+1,s+w[i]);

  ④ 当i=1时,若已测试完所有顶点覆盖方案,外层调用就全部结束;

  d. 主函数调用一次cut(1,0)即可完成整个回溯搜索过程,最终得到的bestw即为所

  求最小顶点权之和。

源程序:

  #include<stdio.h>

  #define MIN 100000

  int m,n,u,v,bestw;

  int e[100][100],w[100],c[100];

  int cover()

  {

  int i,j,t;

  i=1;

  while (i<=n)

  {

  t=0;

  if(c[i]==0)

  {

  j=1;

  while(j<i)

  {

  if(e[j][i]==1&&c[j]==1)

  t=1;

  j++;

  }

  j++;

  while(j<=n)

  {

  if(e[i][j]==1&&c[j]==1)

  t=1;

  j++;

  }

  if(t==0)

  return 0;

  }

  i++;

  }

  return 1;

  }

  void cut(int i,int s)

  {

  if(s>=bestw)

  return;

  if(i>n)

  {

  if(cover())

  bestw=s;

  return;

  }

  c[i]=0;

  cut(i+1,s);

  c[i]=1;

  cut(i+1,s+w[i]);

  }

  main()

  {

  int i,j,k;

  scanf("%d%d",&n,&m);

  for(i=1;i<=n;i++)

  {

  scanf("%d",&w[i]);

  c[i]=0;

  

  }

  for(i=1;i<=n;i++)

  for(j=1;j<=n;j++)

  e[i][j]=0;

  for(k=1;k<=m;k++)

  {

  scanf("%d%d",&u,&v);

  e[u][v]=1;

  }

  bestw=MIN;

   cut(1,0);

  printf("%d",bestw);

  return 0;

  }

posted on 2014-04-26 18:51  石头巴拉  阅读(3244)  评论(0编辑  收藏  举报

导航