您的位置:首页 > 其它

图论——最小生成树

2015-02-21 17:01 344 查看
poj 3723(Kruskal)

从给出的数据可以看出,其不一定是树,更可能是森林,并且根据题意是要求边的总和最大化。故相对的挑选Kruskal算法,而不是prim,只需将权值改为负数即可等效为求最小生成树。

同时注意,所给的示例中我们得注意到,他有可能给同样的girl和boy不同的数值,如第二组测试数据中既有 “2 4 9820”,又有“2 4 8326”,这时我们要挑最大的那个值作为边的权值存储。

#include<iostream>
#include<cstring>
#include<string>
#include<cstdio>
#include<algorithm>
using namespace std;
#define MAX 50050
int father[MAX], son[MAX];
int v, l;

typedef struct Kruskal { //存储边的信息
int a;
int b;
int value;
};

bool cmp(const Kruskal & a, const Kruskal & b) {
return a.value < b.value;
}

int unionsearch(int x) { //查找根结点+路径压缩
return x == father[x] ? x : unionsearch(father[x]);
}

bool join(int x, int y) { //合并
int root1, root2;
root1 = unionsearch(x);
root2 = unionsearch(y);
if(root1 == root2) //为环
return false;
else if(son[root1] >= son[root2]) {
father[root2] = root1;
son[root1] += son[root2];
} else {
father[root1] = root2;
son[root2] += son[root1];
}
return true;
}

int main() {
int ncase, ltotal, sum, flag,boy , girl;
Kruskal edge[MAX];
scanf("%d", &ncase);//原先用cin超时了
//cin>>ncase;
while(ncase--) {
scanf("%d%d%d", &girl, &boy, &l);
//cin>>girl>>boy>>l;
v = girl + boy;
ltotal = 0, sum = 0, flag = 0;
for(int i = 0; i <= v; ++i) { //初始化
father[i] = i;
son[i] = 1;
}
for(int i = 1; i <= l ; ++i) {//初始化
edge[i].value = 0;
}
for(int i = 1; i <= l ; ++i) {

int A,B,V;
//cin>>A>>B>>V;
scanf("%d%d%d", &A, &A, &V);
if(V > -edge[i].value) {//使所输入的边权值最大
edge[i].a = A;
edge[i].b = B+girl;
edge[i].value = -V;

}
}
sort(edge + 1, edge + 1 + l, cmp); //按权值由小到大排序
for(int i = 1; i <= l; ++i) {
if(join(edge[i].a, edge[i].b)) {
ltotal++; //边数加1
sum += edge[i].value; //记录权值之和
//cout<<edge[i].a<<"->"<<edge[i].b<<" = "<<edge[i].value<<endl;
}
}
printf("%d\n", sum+10000*v);
}
return 0;
}


代码比较耗时,还有可以改进的地方。仅供参考!

poj 1789(prim)

题意:

数据中给出的每行字符串代表一种货车,货车可由其他货车“衍生”,现在问:在最佳“衍生”关系的条件下,求“ the highest possible quality of a derivation plan. ”,即“衍生”关系中父子的字符串中不同的字母的个数和。

以测试数据为例:



如上图所示,当2,3,4都被1“衍生”出来时便是最佳“衍生”关系,此时的 the highest possible quality of a derivation plan. ”就等于1/3。

代码如下:

#include<iostream>
#include<string.h>
#include<fstream>
using namespace std;
#define Max_N 2002
char truck[Max_N][8];
int dis[Max_N][Max_N] = {0};
int N;
#define inf 0x3f3f3f3f
bool vis[Max_N];
int lowc[Max_N];
void find_dis() {//找出各顶点间的关系
for(int i = 0; i<N; i++) {
for(int j=i; j<N; j++) {
int temp_num = 0;
if(i == j) {
dis[i][j] = 7;
continue;
}
for(int k =0; k<7; k++) {

if(truck[i][k] != truck[j][k]) {
temp_num++;
}
}
dis[i][j] = temp_num;
dis[j][i] = temp_num;
}
}
}
int prim() {
int i, j, p;
int minc, res = 0;
memset(vis, 0, sizeof(vis));
vis[0] = 1;
for (i=1; i<N; i++) lowc[i] = dis[0][i];
for (i=1; i<N; i++) {
minc = inf;
p = -1;
for (j=0; j<N; j++)
if (0 == vis[j] && minc > lowc[j]) {
minc = lowc[j];
p = j;
}
if (inf == minc) return -1; // 原图不连通
res += minc;
vis[p] = 1;
for (j=0; j<N; j++)
if (0 == vis[j] && lowc[j] > dis[p][j])
lowc[j] = dis[p][j];
}
return res;
}

int main() {
//ifstream in("C://a.txt",std::ios::in);
memset(truck,NULL,sizeof(truck));
while(cin>>N , N!= 0) {
cin.getline(truck[0],8);
for(int i=0; i<N; i++) {
cin.getline(truck[i],8);
}
find_dis();
cout<<"The highest possible quality is 1/"<<prim()<<"."<<endl;
}
}


如有错误,还望指出!

转载请注明出处:http://blog.csdn.net/big_heart_c
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: