• 最小权顶点覆盖问题


    问题描述:

      给定一个赋权无向图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;

      }

  • 相关阅读:
    设计模式(行为模式)之 观察者模式
    java 内存区域 (程序计数器)
    java 枚举的应用
    ServiceLoad 应用(链式编程:统一执行某一类功能、、分支语句优化)
    python前端学习之css
    python学习四十四天(前端之HTML标签)
    python学习四十三天(网络IO模型)
    python学习四十二天(协程)
    python学习四十一天(线程)
    python学习四十天(进程池)
  • 原文地址:https://www.cnblogs.com/wangxiaochu/p/3691903.html
Copyright © 2020-2023  润新知