我正在尝试编写一个 DP 算法来计算我们需要选择的最小顶点数,以便覆盖图上的 k 个边。
到目前为止我写的代码是:
#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);
}
由于某种原因,此代码产生了错误的输出。但是,如果它是正确的,我怀疑它不会很快(指数复杂度)。你能推荐一个算法吗?
示例:对于输入:9 6 1 2 1 3 1 4 2 5 2 6 3 7 4 8 4 9
预期输出为 2
我的程序输出 0。
在看到下面的答案后,我想出了以下代码:
#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));
}