简体   繁体   English

用最少的顶点数覆盖 k 条边

[英]Covering k edges with minimum number of vertices

I am trying to write a DP algorithm that calculates the minimum number of vertices we need to select in order to cover k edges on a graph.我正在尝试编写一个 DP 算法来计算我们需要选择的最小顶点数,以便覆盖图上的 k 条边。

The code I have written so far is:到目前为止我写的代码是:

#include<iostream>

#include<vector>

#include<list>

#include<set>
#include<algorithm> 
#include <tuple>

using namespace std;

int edges[10000][10000]={0}; //which edges I have covered
int adjacency[10000][10000]={0}; //the graph in an array
int K;
int sum=0;

int DP(int i,int j){
    if (j==K) return 1;
    int neys=0; //number of neighbors
    for (int m=0; m<10000; m++){ //scan the neighbor array
         if(adjacency[i][m]==1) {  //if I find a neighbor
            if(edges[i][m]==0) neys++; //if I have not taken this edge before into consideration
            edges[i][m]=1; //mark it as covered
         }
    }
    printf("i: %d\n",i);
    for (int m=0; m<10000; m++) //for all neighbors of i
        if(adjacency[i][m]==1) { //if m is a neighbor
            sum=min(1+DP(m,j+neys),DP(m,j)); //then take the minimum if I include it or not
            printf("sum: %d\n",sum);
        }
    return sum;
}

int main() {

    int N;
    int begin;
    scanf("%d %d",&N,&K);


    for (int i = 0; i < N - 1; i++) {

        int u,v;

        scanf("%d %d",&u,&v);
        if (i==0) begin=u;
        adjacency[u][v]=1;


    }

    int sol=DP(begin,0);
    printf("%d\n",sum);
}

This code is producing the wrong output for some reason.由于某种原因,此代码产生了错误的输出。 However, if it was right I suspect it would not be very fast(exponential complexity).但是,如果是对的,我怀疑它不会很快(指数复杂度)。 Can you suggest an algorithm?你能推荐一个算法吗?

Example: for input: 9 6 1 2 1 3 1 4 2 5 2 6 3 7 4 8 4 9示例:对于输入:9 6 1 2 1 3 1 4 2 5 2 6 3 7 4 8 4 9

The expected output is 2预期输出为 2

My program outputs 0.我的程序输出 0。

After seeing an answer below I came up with the following code:看到下面的答案后,我想出了以下代码:

#include <iostream>
#include <tuple>
#include <bits/stdc++.h>

using namespace std;

using MyKey = tuple<int, int, int, int>;

map<MyKey, int> glob;

int numEdges[100000];

tuple<int,int> compareAndGetBest(tuple<int,int> a, tuple<int,int> b){
 if (get<0>(a) == get<0>(b)){
    if (get<1>(a) >= get<1>(b)) return a;
    else return b;
 }
 else {
    if (get<0>(a) < get<0>(b)) return a;
    else return b;
 }
}

tuple<int,int> f(vector<vector<int>> map, int u, int i,int k,int childEdge){
  //printf("u: %d , i: %d k: %d childEdge: %d\n",u,i,k,childEdge);
  if (!glob[{u,k,i,childEdge}]==0) return make_tuple(glob[{u,k,i,childEdge}],k);


  tuple <int,int> result;

  if (k <= 0){
    result=make_tuple(0,0);
    glob[{u,k,i,childEdge}]=get<0>(result);
    return result;
  }


  if (i < 0){
    result=make_tuple(1000000,0);
    glob[{u,k,i,childEdge}]=get<0>(result);
    return result;
  }


  tuple <int,int> best = f(map, u, i-1, k, childEdge);



  int v = map[u][i];

  if (map[v].size()==0){  
    glob[{u,k,i,childEdge}]=get<0>(best);   
    return best;
  }


  int max = min(k, numEdges[v]);

  int l = map[v].size();


  for (int j=1; j<=max; j++){
    int max_j = (j - l);
    tuple <int,int> a   = f(map, v, l-1, max_j, 0);
    tuple <int,int> fa  = f(map, u, i-1, k-max_j-l-childEdge, childEdge);

    tuple <int,int> b  = f(map, v, l-1, j, 1);
    tuple <int,int> fb = f(map, u, i-1, k-j, childEdge);


    get<0>(a)  = get<0>(a) + 1;
    get<1>(a)  = get<1>(a) + l + childEdge;


    tuple <int,int> na = make_tuple(get<0>(a) + get<0>(fa), get<1>(a) + get<1>(fa));

    tuple <int,int> nb = make_tuple(get<0>(b) + get<0>(fb), get<1>(b) + get<1>(fb));

    best = compareAndGetBest(best, compareAndGetBest(na, nb));

  }

  glob[{u,k,i,childEdge}]=get<0>(best);
  return best;
}

int getNumEdges(vector<vector<int>> map,int u){
    int count=0;

    if (map[u].size()==0){
        return 0;
    }

    else {
        for (auto v: map[u]){
            if (map[v].size()>0){
                numEdges[v]=getNumEdges(map,v);
                count += 1 + numEdges[v];
            }
            else count +=1;
        }
    }

    numEdges[u]=count;

    return numEdges[u];

}

int main(int argc,char **argv){
    int N,K;
    FILE *fp;
    vector<vector<int> > myvec;
    fp=fopen(argv[1],"r");
    fscanf(fp,"%d %d",&N,&K);
    myvec.resize(N+1);
    for(int i=1 ; i<N ; i++){
        //printf("i: %d \n",i);
        int u, v;
        fscanf(fp,"%d %d",&u,&v);
        myvec[u].push_back(v);
    }

    int whatever=getNumEdges(myvec,1);
    //for (int k=1;k<=N-1;k++) printf("numEdges[%d]= %d \n",k,numEdges[k]);

    int l = myvec[1].size();

    tuple<int,int> a = f(myvec, 1, l-1, K, 1);
    tuple<int,int> b = f(myvec, 1, l-1, K-l, 0);

    tuple<int,int> ans=compareAndGetBest(a, make_tuple(get<0>(b)+1,get<1>(b)+l));
    printf("%d\n",get<0>(ans));
}

(This answer applies to trees, which seems to be what this question is about, given a strikingly similar one here and a closed one here .) (这个答案适用于树木,这似乎是什么这个问题是关于,给出惊人相似的一个位置和闭合一个在这里。)

Here's a naive recursion in JavaScript (heavily commented) that uses a simple map of each parent vertex to its children, that's also decorated with the number of edges in the subtree.这是 JavaScript 中的一个天真的递归(大量注释),它使用每个父顶点到其子节点的简单映射,它还用子树中的边数装饰。 (The code could benefit from more example cases to refine with, or possibly rule the concept incorrect.) (代码可以从更多示例案例中受益以进行改进,或者可能规则概念不正确。)

The idea is to treat each child together with its parent, where if the parent is selected, the caller has already subtracted the edges to the children from k .这个想法是将每个孩子与其父母一起对待,如果选择了父母,调用者已经从k减去了孩子的边缘。 Recursive calls go both back to an earlier child (with the same parent-assignment state), as well as trying different values of k from the current subtree, either selecting or skipping the child itself, a choice featured in the recursion.递归调用既可以返回到较早的子节点(具有相同的父赋值状态),也可以从当前子树尝试不同的k值,选择或跳过子节点本身,这是递归中的一个选择。

The recurrence returns a tuple, (c, m) , where c is the minimal cost (number of vertices) and m is the number of edges covered (which could be greater than k ).循环返回一个元组(c, m) ,其中c是最小成本(顶点数), m是覆盖的边数(可能大于k )。

Each node has a search space of O(|edges in subtree|) .每个节点都有一个O(|edges in subtree|)的搜索空间。 Seems like O(|V| * k) might be possible?似乎O(|V| * k)可能是可能的?

 // Returns a tuple, `(c, m)`, where `c` // is the cost (number of vertices) and `m` // is the number of edges covered (which // could be greater than `k`). // 'u' is the root of the tree/subtree, // 'i' is the index of a child of 'u', // 'childEdge' is 1 if the root is // not used, matching the edge count // we can add to each child chosen. // If 'childEdge' is 0, it implies // k was already adjusted by the caller. function f(map, u, i, k, childEdge){ // Base case if (k <= 0) return [0, 0] // Recursion limit if (i < 0) return [Infinity, 0] // Without the ith child let best = f(map, u, i-1, k, childEdge) // Current child let v = map[u].children[i] // Child has no subtree, // it's never optimal to use a leaf if (!map[v]) return best /* Try different edge quantities from the subtree */ let max = Math.min(k, map[v].numEdges) let l = map[v].children.length for (let j=1; j<=max; j++){ // If we choose the child, subtract // its children's count but apply a 0 // childEdge, as well as any childEdge // for the child-as-parent. numEdges includes // edges from the child-as-parent, subtract them. let max_j = (j - l) let [ac, am] = f(map, v, l-1, max_j, 0) let [fac, fam] = f(map, u, i-1, k-max_j-l-childEdge, childEdge) let [bc, bm] = f(map, v, l-1, j, 1) let [fbc, fbm] = f(map, u, i-1, kj, childEdge) // Add 'v' and the edges to its // children to the branch // where 'v' was used. ac = ac + 1 am = am + l + childEdge let a = [ac + fac, am + fam] let b = [bc + fbc, bm + fbm] // Choose between a and b best = compareAndGetBest( best, compareAndGetBest(a, b) ) } return best } // [c, m] are [cost, num_edges_covered] // Return larger m if possible function compareAndGetBest(a, b){ if (a[0] == b[0]){ return a[1] >= b[1] ? a : b } else { return a[0] < b[0] ? a : b } } function getNumEdges(map, u){ if (!map[u]){ return 0 } else { let count = 0 for (let v of map[u].children){ if (map[v]){ map[v]["numEdges"] = getNumEdges(map, v) count += 1 + map[v]["numEdges"] } else { count += 1 } } return map[u]["numEdges"] = count } } function getChildrenMap(edges){ return edges.reduce(function(acc, [u, v]){ if (acc[u]) acc[u].children.push(v) else acc[u] = {children: [v]} return acc }, {}) } function partialVertexCover(edges, k){ var childrenMap = getChildrenMap(edges) getNumEdges(childrenMap, 1) var l = childrenMap[1].children.length console.log(JSON.stringify(childrenMap) + "\\n") let a = f(childrenMap, 1, l-1, k, 1) let [bc, bm] = f(childrenMap, 1, l-1, kl, 0) return compareAndGetBest(a, [bc + 1, bm + l]) } function main(){ var edges = [ [1, 2], [1, 3], // 1 [1, 4], // / | \\ [2, 5], // 2 3 4 [2, 6], // / \\ | / \\ [3, 7], // 5 6 7 8 9 [4, 8], [4, 9] ] var k = 6 console.log(partialVertexCover(edges, k) + "\\n") edges = [ [1, 2], [1, 3], // 1 [1, 4], // / | \\ [2, 5], // 2 3 4 [3, 6], // | | | [4, 7] // 5 6 7 ] console.log(partialVertexCover(edges, k) + "") } main()

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM