求一般图的最小顶点覆盖集问题的混合贪婪算法(近似算法)

Posted tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了求一般图的最小顶点覆盖集问题的混合贪婪算法(近似算法)相关的知识,希望对你有一定的参考价值。

之前准备做hiho一下的时候,网上查关于无向图的最大独立集;

看到了一篇论文,说是能“求一般图的最小顶点覆盖集问题”的混合贪婪算法;

我一看觉得挺牛逼的啊,跑去研究了大半天的这篇论文,发现实际是求近似解的,在特殊情况下偏差极大;

实现完之后拿去做题,发现连样例都过不了,差点还以为程序哪里写挫了,

仔细一看,正好样例产生的无向图就是一个对本算法十分不友好的情况,

看来想在搞算法题的时候用是不大现实了,不过好歹算是研究了一篇论文,还手动实现了一遍;

当然,这个算法在图的规模较大的情况下,应该拥有较好的近似比,可以考虑在某些特定场景下使用;

论文链接clickhere

具体实现:

  1 #include<cstdio>
  2 #include<cstring>
  3 #include<vector>
  4 #include<queue>
  5 #include<algorithm>
  6 #define MAX 20
  7 using namespace std;
  8 int n,m;
  9 struct Edge{
 10     int u,v;
 11 };
 12 struct Point{
 13     int id;
 14     int degree,adj_degree;
 15 }point[MAX];
 16 vector<Edge> E;
 17 vector<int> G[MAX];
 18 int degree[MAX],adj_degree[MAX];//每个点的度数和邻接度数
 19 bool del[MAX],vis[MAX];
 20 int V_cnt,Vv_cnt,E_cnt;
 21 void init_edge()
 22 {
 23     E.clear();
 24     for(int i=1;i<=n;i++) G[i].clear();
 25 }
 26 void add_edge(int u,int v)
 27 {
 28     E.push_back((Edge){u,v});
 29     E.push_back((Edge){v,u});
 30     int _size=E.size();
 31     G[u].push_back(_size-2);
 32     G[v].push_back(_size-1);
 33 }
 34 bool cmp(Point a,Point b){return a.adj_degree>b.adj_degree;}
 35 int pretreat()
 36 {
 37     for(int i=1;i<=n;i++)
 38     {
 39         point[i].degree=0;
 40         if(del[i]) continue;
 41         for(int j=0,_size=G[i].size();j<_size;j++)
 42         {
 43             Edge& e=E[G[i][j]];
 44             if(!del[e.v]) point[i].degree++;
 45         }
 46         if(point[i].degree==0) del[i]=1;
 47     }
 48     for(int i=1;i<=n;i++)
 49     {
 50         if(del[i])
 51         {
 52             point[i].adj_degree=0;
 53             continue;
 54         }
 55         point[i].adj_degree=point[i].degree;
 56         for(int j=0,_size=G[i].size();j<_size;j++) point[i].adj_degree+=point[E[G[i][j]].v].degree;
 57         printf("adj_degree[%d] = %d\\n",i,point[i].adj_degree);
 58     }
 59     sort(point+1,point+n+1,cmp);
 60 }
 61 void MinVC_MGA(bool ans[])
 62 {
 63     memset(del,0,sizeof(del));
 64     for(int i=1;i<=n;i++) point[i].id=i;
 65     E_cnt=0;
 66     while( E_cnt < m )
 67     {
 68         memset(vis,0,sizeof(vis));
 69         pretreat();
 70         V_cnt=0;
 71         Vv_cnt=0;
 72         for(int i=1;i<=n;i++) if(!del[i]) Vv_cnt++;
 73         for(int i=1;i<=n;i++)
 74         {
 75             printf("del[%d]=%d vis[%d]\\n",point[i].id,del[point[i].id],point[i].id,vis[point[i].id]);
 76             if(del[point[i].id]) continue;
 77             if(vis[point[i].id]) continue;
 78             printf("now ans add: %d\\n",point[i].id);
 79             ans[point[i].id]=1;//加入到最小顶点覆盖集中
 80             del[point[i].id]=1, Vv_cnt--;
 81             for(int j=0,_size=G[point[i].id].size();j<_size;j++)
 82             {
 83                 Edge& e=E[G[point[i].id][j]];
 84                 if(del[e.v]) continue;
 85                 E_cnt++;
 86                 if(!vis[e.v])
 87                 {
 88                     vis[e.v]=1;
 89                     V_cnt++;
 90                 }
 91             }
 92             if(V_cnt>=Vv_cnt) break;
 93         }
 94     }
 95 }
 96 
 97 int main()
 98 {
 99     while(scanf("%d %d\\n",&n,&m)!=EOF)
100     {
101         init_edge();
102         for(int i=1,u,v;i<=m;i++)
103         {
104             scanf("%d%d",&u,&v);
105             add_edge(u,v);
106         }
107         bool ans[n+5];
108         memset(ans,0,sizeof(ans));
109         MinVC_MGA(ans);
110         for(int i=1;i<=n;i++) printf("%d:%s\\n",i,ans[i]?"YES":"NO");
111     }
112 }
113 /*
114 13 17
115 1 10
116 1 2
117 1 7
118 10 11
119 7 11
120 7 3
121 7 8
122 11 8
123 3 4
124 4 9
125 8 9
126 8 12
127 9 12
128 5 9
129 12 13
130 5 6
131 6 13
132 */

以上是关于求一般图的最小顶点覆盖集问题的混合贪婪算法(近似算法)的主要内容,如果未能解决你的问题,请参考以下文章

二分图的最小顶点覆盖 最大独立集 最大团

二分图的最小顶点覆盖 最大独立集 最大团

Prim算法求最小生成树

什么是最简单,最简单的算法,用于查找10 ^ 5阶的完整图的EMST

图的最小生成树算法?

怎么求一幅图像的最小生成树