/*
这题求的是一个K度最小生成树的题:
第一步:
先忽略Park点,得到一个森林,再用krusakl算法,就是一个M个最个生成树;
第二步:
再从根节点,选择一个最小的边,连上M个最小生成树,
第三步:
如果还有多余的度用:没有就结束;
那么就分别从根节点上没用上的边,一一计算,加上这个根节点的边
会构成一个环,去掉环中一个权值最大的边,保存差值,
这样一来,那么每一个边就有一个差值,选取最大的那一个差值的边,加上,
并删去环中,最大的边。
然后回到第三步;
第四步:
求出最终结果,并输出;
优化思路:
在第三步中,其实没必要,重复计算根节点上的每一条边的差值,只需要
在上一步中,更新被操作的一个子树,连接这一棵子树的根节点上的边的差值
更新新一下就好了,不要再重复计算;
由于,我的目标要求不高,也没那么多时间,过了就好了,所以此代码没优化;
注意的点:
1,思路想好了,但是在写代码的时候,一定要注意逻辑,写起来好麻烦,
2,我的第一次的写的时候,用的是PRIM算法写的,不于通过,用kruskal算法就给过了
不知道,对用什么算法写,还有要求;
*/
#include <iostream>
#include <sstream>
#include <cstring>
#include <string>
#include <map>
#include <iomanip>
#include <vector>
#include <algorithm>
using namespace std;
typedef struct Edge{
int u,v,d;
Edge(int a,int b, int c){
u = a;
v = b;
d = c;
}
} Edge;
const int MAX = 40;
const int INF = 1000;
int element = 0;
int maze[MAX][MAX];
int prim_maze[MAX][MAX];
int K;
map<string, int> mp;
int v_flag[MAX];
vector<Edge> edges;
bool GreaterSort (Edge a,Edge b) { return (a.d<b.d); }
int find(int x){
if(v_flag[x] == x){
return x;
}else{
return find(v_flag[x]);
}
}
void un(int a,int b){
v_flag[a] = v_flag[b];
}
//kruskal 算法一定要用到并查集,适用于,森林求最生小生成树;
void kruskal(){
int find_sign = 0;
sort(edges.begin(), edges.end(), GreaterSort);
for(int i=1; i<=element; ++i){
v_flag[i] = i;
}
for(int i=0; i<edges.size(); ++i){
int p = edges[i].u;
int q = edges[i].v;
int d = edges[i].d;
int a = find(p);
int b = find(q);
if(mp["Park"] == q || mp["Park"] == p ||
(a==b)) continue;
un(a, b);
prim_maze[p][q] = prim_maze[q][p] = d;
}
}
void dfs(int a,int b,int root){
v_flag[a] = v_flag[b] = 1;
for(int i=1; i<=element; ++i){
if(v_flag[i]!=1 && prim_maze[b][i]!=INF){
dfs(b, i, root);
}
}
}
int l_sign = 0;
void l_dfs(int root, int a, int b, Edge *e, Edge te, Edge *del){
v_flag[b] = 1;
if(l_sign == 1) return ;
if(root == a){
del->u = root;
del->v = b;
}
if(prim_maze[a][b] > te.d && prim_maze[a][b] != INF){
e->u = te.u = a;
e->v = te.v = b;
e->d = te.d = prim_maze[a][b];
}
if(b == root){
e->u = te.u;
e->v = te.v;
e->d = te.d;
l_sign = 1;
return ;
}
for(int i=1; i<=element; ++i){
if(v_flag[i]==0 && prim_maze[b][i]!=INF){
l_dfs(root, b, i, e, te, del);
}
}
}
void solve(int root){
//第二步, 将所有的根节点的边放到一个集合里,枚举每一条边,连接其他树;
int root_count = 0;
vector<Edge> root_edges;
for(int i=1; i<=element; ++i){
if(maze[root][i] != INF && maze[root][i] != 0){
root_edges.push_back(Edge(root, i, maze[root][i]));
}
}
sort(root_edges.begin(), root_edges.end(), GreaterSort);
for(int i=1; i<=element; ++i){
v_flag[i] = 0;
}
for(int i=0; i<root_edges.size(); ++i){
if(v_flag[root_edges[i].v] == 0){
dfs(root_edges[i].u, root_edges[i].v, root);
prim_maze[root_edges[i].v][root_edges[i].u] =
prim_maze[root_edges[i].u][root_edges[i].v] =
maze[root_edges[i].v][root_edges[i].u];
++root_count;
if(root_count >= K) break;
}
}
//第三步, 松弛操作
while(root_count<K){
Edge *len = new Edge(0, 0, 0);
Edge *finish = new Edge(0, 0, 0);
Edge *del = new Edge(0,0,0);
int temp = 0;
for(int i=1; i<=element; ++i) {
if(maze[root][i] != INF && prim_maze[root][i] == INF ){
for(int i=1; i<=element; ++i) v_flag[i] = 0;
len->d = 0;
l_sign = 0;
l_dfs(root, root, i, len, Edge(0,0,0), del);
len->d -= maze[root][i];
if(len->d > finish->d){
finish->u = len->u;
finish->v = len->v;
finish->d = len->d;
temp = i;
}
}
}
prim_maze[finish->u][finish->v] = prim_maze[finish->v][finish->u] = INF;
prim_maze[root][temp] = prim_maze[temp][root] = maze[temp][root];
++root_count;
}
//第四步,输出结果;
int ans = 0;
for(int i=1; i<=element; ++i) {
for(int j=1; j<=element; ++j){
if(prim_maze[i][j] != INF)
ans+=prim_maze[i][j];
}
}
printf("Total miles driven: %d\n", ans/2);
}
int main(){
int count, num;
char str1[40], str2[40];
while(~scanf("%d", &count)){
element = 0;
mp.clear();
edges.clear();
for(int i=1; i<MAX; ++i){
for(int j=1; j<MAX; ++j){
prim_maze[i][j] = maze[i][j] = prim_maze[j][i] = maze[j][i] = INF;
}
}
mp["Park"] = ++element;
for(int i=1; i<=count; ++i){
scanf("%s %s", str1, str2);
scanf("%d", &num);
if(mp[str1] == 0)
mp[str1] = ++element;
if(mp[str2] == 0)
mp[str2] = ++element;
maze[mp[str1]][mp[str2]] = maze[mp[str2]][mp[str1]] = num;
edges.push_back(Edge(mp[str1], mp[str2], num));
}
scanf("%d", &K);
//第一步: 除了根节点外,对森林做最小生成树的操作;
kruskal();
solve(mp["Park"]);
}
return 0;
}
POJ 1639(kruskal, dfs, )
最新推荐文章于 2021-05-11 17:15:21 发布