nyoj 38 http://acm.nyist.net/JudgeOnline/problem.php?pid=38
prim 克鲁斯卡尔 两个算法
首先说说 克鲁斯卡尔算法,按照边的从小到大排序之后,利用并查集的思想,不断并。直到并出n-1条边。
#include<stdio.h> #include<iostream> #include<string.h> #include<string> #include<algorithm> #include<queue> #include<cmath> using namespace std; typedef long long int LL; const int INF=2e9+1e8; const double eps=1e-8; const int MM=500+5; struct Edge { int s,t,val; }; Edge edge[MM*MM/2]; int m,n; int pre[MM]; void init_pre() { for(int i=0; i<=n; i++) pre[i]=i; } bool cmp(Edge a,Edge b) { return a.val<b.val; } int getfa(int x) { return pre[x]==x?x:pre[x]=getfa(pre[x]); } bool merges(int x,int y) { int fx=getfa(x),fy=getfa(y); if(fx==fy) return false; else { pre[fx]=fy; return true; } } int Kruskal() { sort(edge+1,edge+1+m,cmp); int tot=0; for(int i=1; i<=m; i++) { if(merges(edge[i].s,edge[i].t)) { tot+=edge[i].val; } } return tot; } int main() { int ncase; scanf("%d",&ncase); while(ncase--) { scanf("%d%d",&n,&m); init_pre(); for(int i=1; i<=m; i++) { scanf("%d%d%d",&edge[i].s,&edge[i].t,&edge[i].val); } int minn=INF; for(int i=1; i<=n; i++) { int temp; scanf("%d",&temp); minn=min(temp,minn); } printf("%d ",Kruskal()+minn); } return 0; }
prim
1).输入:一个加权连通图,其中顶点集合为V,边集合为E;
2).初始化:Vnew = {x},其中x为集合V中的任一节点(起始点),Enew =
{},为空;
3).重复下列操作,直到Vnew = V:
b.将v加入集合Vnew中,将<u, v>边加入集合Enew中;
#include<iostream> #include<algorithm> #include<stdio.h> #include<string.h> #include<math.h> using namespace std; const int maxn=505; const int INF=0x3f3f3f3f; int map[maxn][maxn]; int dis[maxn]; int vis[maxn]; int N;//N组测试数据 int V;//点的数量 int E;//边的数量 int min_num;//最小外接花费 void init() { scanf("%d%d",&V,&E); for(int i=0; i<=V; i++)//初始化图 for(int j=0; j<=V; j++) i==j?map[i][j]=0:map[i][j]=INF; while(E--)//建图 { int a,b,c; scanf("%d%d%d",&a,&b,&c); map[a][b]=c;//无向图 map[b][a]=c; } min_num=INF; for(int i=1; i<=V; i++) { int x; scanf("%d",&x); min_num=min(min_num,x);//生成树连接到外界的最小花费 dis[i]=map[i][1];//从1开始构造最小生成树 } memset(vis,0,sizeof(vis)); vis[1]=1;//0代表是外界 } void Prim() { int min_cost=0;//初始化最小花费 for(int i=1; i<V; i++) { int minn=INF; int point_minn; for(int j=1; j<=V; j++) if(vis[j]==0&&minn>dis[j]) { point_minn=j; minn=dis[j]; } if(minn==INF) break; min_cost+=dis[point_minn]; vis[point_minn]=1; for(int j=1; j<=V; j++) if(vis[j]==0&&dis[j]>map[point_minn][j]) dis[j]=map[point_minn][j]; } printf("%d ",min_cost+min_num); } int main() { scanf("%d",&N); while(N--) { init(); Prim(); } return 0; }