很好的解题报告:
http://blog.csdn.net/new_c_yuer/article/details/6365689
注意两点:
1.预处理环中权值最大的边····
2.可以把去掉度限制后的点看成是连通的,权值为无穷远的点也看做是连通的,反正后面肯定会替换出来的····
我的代码没有预处理出权值最大的边,但是第2点事做到了的,这样便于代码的实现·····
贴代码:
1 #include <cstdio> 2 #include <iostream> 3 #include <map> 4 #include <string> 5 #include <algorithm> 6 #define INF 0x3f3f3f3f 7 #define N 505 8 using namespace std; 9 map<string,int> ma; 10 map<string,int>::iterator it; 11 int n,k;//点的个数,度数限制 12 bool flag; 13 long long int ans;//最后的结果 14 bool in[N][N],vis[N];//加入最小生成树中的边 15 int edge[N][N],pre[N], next[N],lowcost[N];//边,确定哪些边被加入了最小生成树中,存环中的边,求最小生成树 16 int Find(char c[]) 17 { 18 it = ma.find(c); 19 if(it != ma.end()) 20 return it->second; 21 ma[c] = ++n; 22 return n; 23 } 24 //用prim函数求一次去掉度限制的点后的最小生成树 25 void prim() 26 { 27 lowcost[1] = -1; 28 for(int i=2; i<=n; ++i) 29 { 30 lowcost[i] = edge[1][i]; 31 pre[i] = 1; 32 } 33 for(int i=2; i<=n; ++i) 34 { 35 int v; 36 int minum=INF; 37 for(int j=2; j<=n; ++j) 38 { 39 if(lowcost[j] != -1 && minum >= lowcost[j]) 40 { 41 minum = lowcost[j]; 42 v = j; 43 } 44 } 45 lowcost[v] = -1; 46 ans += edge[v][pre[v]]; 47 in[v][pre[v]] = in[pre[v]][v] = 1; 48 for(int j=2; j<=n; ++j) 49 { 50 if(lowcost[j] != -1 && lowcost[j] > edge[j][v] ) 51 { 52 lowcost[j] = edge[j][v]; 53 pre[j] = v; 54 } 55 } 56 } 57 } 58 //dfs找出环 59 void dfs(int x) 60 { 61 if(x == 0) 62 { 63 flag = true; 64 return; 65 } 66 vis[x] = 1; 67 for(int i = n; i >= 0; --i) 68 { 69 if(in[x][i] && !vis[i] && !flag) 70 { 71 next[x] = i; 72 dfs(i); 73 } 74 } 75 } 76 //找环上权值最大的边 77 void findMax(int x,int &s,int &e,int &maxnum) 78 { 79 memset(vis,0,sizeof(vis)); 80 flag = false; 81 dfs(x); 82 maxnum = edge[0][x]; 83 int ne = x; 84 while(next[ne] != 0) 85 { 86 if(edge[ne][next[ne]] > maxnum) 87 { 88 maxnum = edge[ne][next[ne]]; 89 s = ne; 90 e = next[ne]; 91 } 92 ne = next[ne]; 93 } 94 } 95 //找度限制为k的最小生成树 96 void kTree() 97 { 98 int minum = INF; 99 int v; 100 for(int i=1; i<=n; ++i) 101 { 102 if(edge[0][i] < minum) 103 { 104 minum = edge[0][i]; 105 v = i; 106 } 107 } 108 in[v][0] = in[0][v] = 1; 109 ans += edge[0][v]; 110 for(int t=1; t<k; ++t) 111 { 112 minum = INF; 113 v = -1; 114 int s,e,m; 115 for(int i=1; i<=n; ++i) 116 { 117 if(!in[0][i] && edge[0][i] < INF) 118 { 119 int ss,ee,maxnum; 120 findMax(i,ss,ee,maxnum); 121 if(edge[0][i] - maxnum < minum) 122 { 123 minum = edge[0][i] - maxnum ; 124 s = ss; 125 e = ee; 126 m = minum; 127 v= i; 128 } 129 } 130 } 131 if(v == -1) break; 132 if(minum >= 0 ) break; 133 in[0][v] = 1; 134 in[v][0] = 1; 135 in[s][e] = 0; 136 in[e][s] =0; 137 ans += minum; 138 } 139 printf("Total miles driven: %d ",ans); 140 } 141 // 初始化输入 142 void initScan() 143 { 144 int m; 145 ma["Park"] = n; 146 scanf("%d",&m); 147 memset(edge,0x3f,sizeof(edge)); 148 for(int i=0; i<m; ++i) 149 { 150 char a1[N],a2[N]; 151 int u,v,w; 152 scanf("%s %s %d",a1,a2,&w); 153 u = Find(a1); 154 v = Find(a2); 155 edge[u][v] = w; 156 edge[v][u] = edge[u][v]; 157 } 158 scanf("%d",&k); 159 } 160 int main() 161 { 162 initScan(); 163 prim(); 164 kTree(); 165 return 0; 166 }