本来是POJ里的一道水题,就尝试用不同的思路去写。因为本来就很习惯用STL,所以就干脆写了个STL版本
基本思路就是构建优先队列,不断查询满足以下条件的边:
1、权值尽可能要小
2、边的两端点一个已经入树,一个还未入树
3、如果优先队列排空后仍然没有合适的边,那么就无法构建最小生成树了
下面是题目传送
不过这个程序POJ上跑的时候,最开始内存爆掉了。我减小了maxn以后才AC了。
可能这也是STL的一个缺陷吧。不过个人看来是数组开的稍微大了些,搞得STL容器没内存了。
下面是代码:
#include<iostream>
#include<algorithm>
#include<string>
#include<cstring>
#include<vector>
#include<stack>
#include<queue>
#include<map>
#include<cstdio>
#define mem(s,value) memset(s,value,sizeof(s))
#define frein(s) freopen(s,"r",stdin)
typedef long long ll;
typedef unsigned long long ull;
using namespace std;
const int maxn = 1e3;
class Edge{
public:
int u,v;
int value;
Edge(){};
Edge(int u_,int v_,int value_):u(u_),v(v_),value(value_){};
bool operator< (const Edge& rhs)const{
//这里一定要注意,优先队列默认大数在前
//这里为了让小数在前,就对运算符进行了修改
return value > rhs.value;
}
};
priority_queue<Edge> Q;
int vis[maxn];
int mapper[maxn][maxn];
int n,k;
int Value;
//核心代码
int solve(){
while(!Q.empty())Q.pop();
vis[1]=1;
Value = 0;
int num = n-1;
int cur = 1;
while(num--){
//对于cur结点,找到所有相关的边并压入优先队列
for(int i=1;i<=n;i++){
if(mapper[cur][i]){
Q.push(Edge(cur,i,mapper[cur][i]));
}
}
//寻找当前可用最短边
Edge aim;
bool ok=false;
//事实上寻找的新的合适的边一定是一个连接了二分图的边
while(!Q.empty()){
aim = Q.top(); Q.pop();
if(vis[aim.v])continue;
ok=true;
break;
}
if(!ok)return 0;//排除找不到的情况
//计算树
vis[aim.v]=1;
Value += aim.value;
cur = aim.v;
}
return 1;
}
int readin(){
memset(mapper,0,sizeof(mapper));
memset(vis,0,sizeof(vis));
scanf("%d",&n);
if(!n)return 0;
scanf("%d",&k);
for(int i=0;i<k;i++){
int a,b,w;
scanf("%d %d %d",&a,&b,&w);
//数据读入这里一定需要注意一下
if(mapper[a][b]==0){
mapper[a][b] = mapper[b][a] = w;
}else{
w = min(w,mapper[a][b]);
mapper[a][b] = mapper[b][a] = w;
}
}
return 1;
}
int main(){
while(readin()){
solve();
cout<<Value<<endl;
}
return 0;
}
OK