题目:
HDU-1863
Kruskal算法:
int f[maxn];
struct node{
int u,v;
int w;
bool operator < (const node &s) const{
return w<s.w;
}
}edge[maxn];
用一个结构体来存储每一条边,f数组用来作点集,即并查集。细心你会发现我重载了小于号,用于对边的权值按从小到大排序,你写成w>s.w就是从大到小了,嘻嘻嘻。
wait,我刚刚说并查集,嘿嘿,没错。我们算法的思想是每次选择价值最小的边,然后选择了之后,就要将这两条边的顶点归入同一个集合。下一次选择的时候就不能再选择这样一条边,即两个顶点都在这个集合的边。我们总共需要选择n-1条边,假设这个图有n个顶点嘛,嘻嘻嘻。
算法复杂度设边数为n,则为O(n^logn)
我们这道题目呢。。。我被它坑了,他n代表边的数量,m代表顶点数量。。。气啊
代码展示:
#include<stdio.h>
#include<iostream>
#include<algorithm>
#include<string>
#include<cstring>
#include<cmath>
#include<stack>
using namespace std;
#define N 100001
#define maxn 3001
typedef long long ll;
int f[maxn];
struct node{
int u,v;
int w;
bool operator < (const node &s) const{
return w<s.w;
}
}edge[maxn];
int fi(int n){
int x=n,r=n,k;
while(x!=f[x]) x=f[x];
while(r!=x){
k=f[r];
f[r]=x;
r=k;
}
return x;
}
int Merge(int a,int b){
int fa=fi(a);
int fb=fi(b);
if(fa!=fb){
f[fa]=fb;
return 1;
}
return 0;
}
int main(){
int n,m,u,v,w,kcount,sum;
while(scanf("%d%d",&n,&m)){
if(n==0) return 0;
kcount=0;
sum=0;
for(int i=0;i<n;i++) scanf("%d%d%d",&edge[i].u,&edge[i].v,&edge[i].w);
for(int i=1;i<=m;i++) f[i]=i;
sort(edge,edge+n);
for(int i=0;i<n;i++){
if(Merge(edge[i].u,edge[i].v)){
kcount++;
sum+=edge[i].w;
}
if(kcount==m-1) break;
}
if(kcount!=m-1) printf("?\n");
else printf("%d\n",sum);
}
return 0;
}
Prim算法:
Prim算法与前一种算法比较更适合于稠密图,因为它不管边的数量再多,它开的数组,即dis,mp,都等于顶点数目大小。设顶点数为n,则该算法时间复杂度为O(n^2)。
算法核心思想:选择一个dis值最小的点为起点,然后开一个dis数组,代表当前点到非生成树点的距离,初始化为1到1~n的距离。与Dijkstra有相似也有不同,相似是都用dis存储距离,都有疏松的思想。不同的是,他每次疏松是比较的是所有非树顶点dis[i]与当前顶点到非树顶点mp[k][i]的大小,即存储的就是当前点到非树顶点的最短距离。我们每次不能对已在生成树中的点进行操作,所以访问过就标记vis[i]=1。由于我们找到一个点疏松边的时候每次比较的是当前点与非树顶点的距离,所以在树中的点就不能进行疏松。
完整代码:
#include<stdio.h>
#include<iostream>
#include<algorithm>
#include<string>
#include<cstring>
#include<cmath>
#include<stack>
using namespace std;
#define N 100001
#define maxn 105
typedef long long ll;
const int inf=0x3f3f3f3f;
int f[maxn],vis[maxn],mp[maxn][maxn],dis[maxn];
int main(){
int n,m,u,v,w,kcount,sum,kmin,k;
while(scanf("%d%d",&n,&m)){
if(n==0) return 0;
memset(vis,0,sizeof vis);
for(int i=1;i<=m;i++){
for(int j=1;j<=m;j++){
if(i!=j) mp[i][j]=inf;
else mp[i][j]=0;
}
}
while(n--){
scanf("%d%d%d",&u,&v,&w);
mp[u][v]=min(mp[u][v],w);
mp[v][u]=min(mp[v][u],w);
}
for(int i=1;i<=m;i++) dis[i]=mp[1][i];
vis[1]=1;
kcount=1,sum=0;
while(kcount<m){
kmin=inf;
for(int i=1;i<=m;i++){
if(vis[i]==0&&kmin>dis[i]){
kmin=dis[i];
k=i;
}
}
vis[k]=1;
kcount++;
sum+=dis[k];
for(int i=1;i<=m;i++){
if(vis[i]==0&&dis[i]>mp[k][i]) dis[i]=mp[k][i];
}
}
int flag=0;
for(int i=1;i<=m;i++) if(dis[i]==inf) flag=1;
if(flag) printf("?\n");
else printf("%d\n",sum);
}
return 0;
}