题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1863
题意:求构成一个连通图的最小代价,一看就是最小生成树。
思路:最小生成树版题。
想用use数组表示两个点是否用过,后来发现这样行不通,因为会忽略链接两个连通子图的边。
源码:
Kruskal:
#include <cstdio>
#include <cmath>
#include <cstring>
#include <string>
#include <iostream>
#include <algorithm>
#include <queue>
#include <vector>
using namespace std;
int const MAXN = 100+2;
int pa[MAXN],use[MAXN],ans,n,m,dot;
struct edge
{
int s,e,val;
void init(int a,int b,int c)
{
s = a; e = b; val = c;
}
}d[MAXN*MAXN];
bool cmp(edge a,edge b)
{
return a.val<b.val;
}
int fi(int a)
{
if(a!=pa[a]) return fi(pa[a]);
return a;
}
void init()
{
for(int i=1; i<=m; i++) pa[i] = i;
memset(use,0,sizeof(use));
int s,e,val;
for(int i=0; i<n; i++){
scanf("%d%d%d",&s,&e,&val);
d[i].init(s,e,val);
}
sort(d,d+n,cmp);
ans = 0;
}
void Kruskal()
{
dot = 1;
for(int i=0; i<n; i++){
int x = fi(d[i].s);
int y = fi(d[i].e);
if(x!=y){
dot++;
pa[x] = y;
ans+=d[i].val;
}
}
}
void solve()
{
if(dot!=m) printf("?\n");
else printf("%d\n",ans);
}
int main()
{
while(scanf("%d%d",&n,&m)!=EOF && n){
init();
Kruskal();
solve();
}
return 0;
}
Prim:
#include <cstdio>
#include <cstring>
#include <cmath>
#include <algorithm>
#include <iostream>
#include <queue>
using namespace std;
int const MAXN = 100+5;
int edge[MAXN][MAXN],use[MAXN],tot,ans,n,m;
struct D
{
int mark,val;
}low[MAXN];
void init()
{
memset(use,0,sizeof(use));
memset(edge,-1,sizeof(edge));
int s,e,val;
while(n--){
scanf("%d%d%d",&s,&e,&val);
edge[e][s] = edge[s][e] = val;
}
tot = 1;
ans = 0;
}
int fi()
{
int flag = 1;
int pos = 1;
for(int i=1; i<=m; i++)
{
if(use[i]==0 && low[i].val!=-1 && (low[i].val<=low[pos].val || low[pos].val==-1)){
flag = 0;
pos = i;
}
}
if(flag) return -1;
else return pos;
}
void Prim()
{
use[1] = 1;
int pos = 1;
for(int i=1; i<=m; i++){///初始化
low[i].mark = 1;
low[i].val = edge[1][i];
}
pos = fi();
tot++;
ans += low[pos].val;
use[pos] = 1;
while(1){
for(int j=1; j<=m; j++){
if(edge[pos][j]!=-1 && use[j]==0 && ((edge[pos][j]<low[j].val) || low[j].val==-1)){
low[j].mark = pos;
low[j].val = edge[pos][j];
}
}
pos = fi();
if(pos != -1){
ans += low[pos].val;
use[pos] = 1;
tot++;
}
else break;
}
}
void solve()
{
if(tot==m) printf("%d\n",ans);
else printf("?\n");
}
int main()
{
while(scanf("%d%d",&n,&m)!=EOF && n){
init();
Prim();
solve();
}
return 0;
}
错误版:
#include <cstdio>
#include <cmath>
#include <cstring>
#include <string>
#include <iostream>
#include <algorithm>
#include <queue>
#include <vector>
using namespace std;
int const MAXN = 100+2;
int pa[MAXN],use[MAXN],ans,n,m,dot;
struct edge
{
int s,e,val;
void init(int a,int b,int c)
{
s = a; e = b; val = c;
}
}d[MAXN*MAXN];
bool cmp(edge a,edge b)
{
return a.val<b.val;
}
int fi(int a)
{
if(a!=pa[a]) return fi(pa[a]);
return a;
}
void init()
{
for(int i=1; i<=m; i++) pa[i] = i;
memset(use,0,sizeof(use));
int s,e,val;
for(int i=0; i<n; i++){
scanf("%d%d%d",&s,&e,&val);
d[i].init(s,e,val);
}
sort(d,d+n,cmp);
ans = 0;
}
void Kruskal()
{
// use[d[0].s] = 1;
// use[d[0].e] = 1;
// ans += d[0].val;
// dot = 1;
for(int i=0; i<n; i++){
if(use[d[i].s]==1 && use[d[i].e]==1)
continue;
use[d[i].s] = 1;
use[d[i].e] = 1;
// int x = fi(d[i].s);
// int y = fi(d[i].e);
// printf("i = %d,x = %d,y = %d\n",i,x,y);
// if(x!=y){
// dot++;
// pa[x] = y;
// ans+=d[i].val;
// }
ans += d[i].val;
}
}
void solve()
{
int flag = 0;
for(int i=1; i<=n; i++){
if(use[i]==0){
flag = 1; break;
}
}
if(flag) printf("?\n");
else printf("%d\n",ans);
}
int main()
{
while(scanf("%d%d",&n,&m)!=EOF && n){
init();
Kruskal();
solve();
}
return 0;
}