您的位置:首页 > 其它

poj 1639 Picnic Planning k限制生成树问题

2014-10-14 19:40 369 查看
题意:有一群兄弟去野餐,可以自己开车到目的地,或者开车到A的家里,然后和A一起去目的地。但目的地的停车场不一定容得下,如果每个人都自己开车去的话。所以这对连接到Park的边数有个限制。求他们总路径的最小值。

本体是一道k度限制生成树问题,可以参看资料:
http://wenku.baidu.com/view/70ef0e00eff9aef8941e06db.html
看后结合代码理解这种题目:当时参考了别人的代码

/*

最小k限制最小生成树;

*/

#include<iostream>

#include<cstdio>

#include <cstring>

#include <map>

#include<string>

using namespace std;

#define inf (1<<30)

#define M 30

int pre[M];

int g[M][M];

int link[M][M];

int vist[M];

map<string,int>name;

struct node {

int u, v, len;

node(){}

node(int u, int v, int len):u(u),v(v),len(len){}

}point[M];

int k;

int root;

int ans;

int n, m;

void init(){

int len;

int u, v;

ans = 0;

char s1[20], s2[20];

memset(g, 0x3f, sizeof(g));

memset(vist, 0, sizeof(vist));

memset(link, 0, sizeof(link));

map<string, int >::iterator it1, it2; //map的应用很好的解决了读入问题;

name.clear();

name["Park"] = 0;

n = 1;

for(int i = 0; i < m; i++){

scanf("%s%s%d", s1, s2, &len);

it1 = name.find(s1);

it2 = name.find(s2);

if(it1 != name.end()) u = it1->second;

else {

name[s1] = n;

u = n++;

}

if(it2 != name.end()) v = it2->second;

else {

name[s2] = n;

v = n++;

}

if(g[u][v] > len)

g[u][v] = g[v][u] = len;

}

// for(int i = 0; i < n; i++)

// for(int j= 0; j < n; j++){

//

// printf("%d %d %d\n", i, j, g[i][j]);

// }

scanf("%d", &k);

}

void prime(int u){

int dis[M];

int minn = inf;

int index = -1;

vist[u] = 1;

memset(pre, -1, sizeof(pre));

for(int i = 1; i < n; i++){

dis[i] = g[u][i];

pre[i] = u;

}

// dis[u] = 0;

while(1){

minn = inf;

index = -1;

for(int i = 1; i < n; i++){

if(!vist[i] && dis[i] < minn){

minn = dis[i];

index = i;

}

}

if(index == -1)

break;

link[pre[index]][index] = link[index][pre[index]] = 1;

vist[index] = 1;

ans += dis[index];

if(g[0][root] > g[0][index])

root = index;

for(int i = 1; i < n; i++){

if(!vist[i] && dis[i] > g[index][i]){

dis[i] = g[index][i];

pre[i] = index;

}

}

}

}

void dfs(int cur, int score, int u, int v){ //cur 当前点, score当前点的前驱,存在最长边的两个点。

for(int i = 1; i < n; i++){

if(i != score && link[cur][i]){ //不是还回边或不在最小生成树中的边。

if(score == -1 || g[cur][i] >= g[u][v]){

point[i] = node(cur, i, g[cur][i]);

dfs(i, cur, cur, i);

}else {

point[i] = node(u, v, g[u][v]);

dfs(i, cur, u, v);

}

}

}

}

void work(){

for(int i = 1; i < n; i++){

if(vist[i]) continue;

k--;

root = i;

prime(i);

ans += g[0][root];

link[0][root] = link[root][0] = 1;

dfs(root, -1, -1, -1);

}

while(k--){

int c= 0, index;

for(int i = 1; i < n; i++){

if(link[0][i] || g[0][i] == inf) continue;

if(g[0][i] - point[i].len < c){

c = g[0][i] - point[i].len;

index = i;

}

}

if(c == 0)

break;

if(c < 0){

link[point[index].u][point[index].v] = link[point[index].v][point[index].u] = 0;

link[0][index] = link[index][0] = 1;

ans += c;

dfs(index, -1, -1, -1);

}

}

printf("Total miles driven: %d\n", ans);

}

int main()

{

while(scanf("%d", &m) != EOF){

init();

work();

}

return 0;

}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: