最小生成树 水题集
来源:互联网 发布:彩票网络开售最新消息 编辑:程序博客网 时间:2024/06/05 21:02
先说求无向图最小生成树的两种算法:
①Prim算法
1.初始时两个集合V,E,初始时V为空,E是所有点的集合。
2.以图中任意一个点为起始点,把这点加入集合V,然后从集合E中删除,然后更新这个点到其它点的距离,如果更新不到的点,那么之间的距离为无穷大。
3.然后挑选离起始点最近的点,把这点加入集合V,然后从集合E中删除(有多个的话任选一个),然后更新 新加入的点 到其它点的距离,然后再找出一个距离这个集合最近的点(这个距离最近的点可能离起始点最近)。
4.然后重复上面的步骤,直至路被更新完或E为空,如果E不为空,说明图不连通。
②克鲁斯卡尔算法
1.将两点之间的距离排序
2.每次从中选出距离最短的两点,判断这两点所在的集合是否联通。
3.如果联通,继续步骤2;如果不连通,将两点合并为一个集合,继续步骤2
4.直至所有点都联通,或路径判断完毕
其中稠密图适合用prim,稀疏图适合用克鲁斯卡尔。
两个算法的基础都是贪心算法,下面的水题,练练手。。。
Hdu 1102 Constructing Roads
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1102
题目大意:给你一个矩阵map,其中map[i][j]表示从i到j的花费,给你多次询问,输出询问的两点之间联通的最小花费
代码如下:
#include<cstdio>#include<cstring>#include<algorithm>using namespace std;#define Maxint 0x3f3f3f3f#define N 110int map[N][N],visit[N],low[N];int n,m;int prim(){ int Min,sum=0,pos,i,j; memset(visit,0,sizeof(visit)); visit[1]=1;pos=1; for(int i=1;i<=n;i++) if(i!=pos) low[i]=map[pos][i]; for(int i=1;i<n;i++) { Min=Maxint; for(int j=1;j<=n;j++) if(visit[j]==0&&low[j]<Min) { Min=low[j]; pos=j; } sum+=Min; visit[pos]=1; for(int j=1;j<=n;j++) if(visit[j]==0&&low[j]>map[pos][j]) low[j]=map[pos][j]; } return sum;}int main(){ while(~scanf("%d",&n)) { for(int i=1;i<=n;i++) for(int j=1;j<=n;j++) {scanf("%d",&map[i][j]);map[j][i]=map[i][j];} scanf("%d",&m); int a,b; for(int i=1;i<=m;i++) { scanf("%d%d",&a,&b); map[a][b]=map[b][a]=0; } printf("%d\n",prim()); } return 0;}
Hdu 1863 畅通工程
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1863
题目大意:中文题,不解释
代码如下:
#include<cstdio>#include<cstring>#include<algorithm>using namespace std;#define Maxint 0x3f3f3f3f#define N 110int n,m,rank,map[N][N],sum,f[N];//克鲁斯卡尔struct point{int x,y,dis;point():x(0),y(0),dis(0){}//结构体的初始化}s[N];bool cmp(point a,point b){ return a.dis<b.dis;}void init(){ sum=0; rank=m; for(int i=0;i<=N;i++) f[i]=i;}int find(int x){ if(x!=f[x]) f[x]=find(f[x]); return f[x];}int merge(point a){ int fx=find(a.x); int fy=find(a.y); if(fx!=fy) { f[fx]=fy; sum+=a.dis; rank--; } return rank;}int main(){ while(scanf("%d%d",&n,&m)&&n) { init(); for(int i=0; i<n; i++) scanf("%d%d%d",&s[i].x,&s[i].y,&s[i].dis); sort(s,s+n,cmp); int i; for(i=0;i<n;i++) { if(merge(s[i])==1) {printf("%d\n",sum);break;} } if(rank>1) printf("?\n"); } return 0;}
Hdu 1875 畅通工程再续
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1875
代码如下:
#include<cstdio>#include<cstring>#include<cmath>#include<algorithm>using namespace std;#define Maxint 0x3f3f3f3f#define N 110//primint visit[N],n;double low[N],map[N][N];struct point{int x;int y;}s[N];void init()//初始化{ for(int i=0;i<N;i++) for(int j=0;j<N;j++) { if(i==j) map[i][j]=0; else map[i][j]=Maxint; }}double prim(){ double Min,sum=0; int pos,i,j; memset(visit,0,sizeof(visit)); visit[0]=1;pos=0; for(int i=0;i<n;i++) if(i!=pos) low[i]=map[pos][i]; for(int i=1;i<n;i++) { Min=Maxint; for(int j=0;j<n;j++) if(visit[j]==0&&low[j]<Min) { Min=low[j]; pos=j; } if(Min==Maxint) return -1; sum+=Min; visit[pos]=1; for(int j=0;j<n;j++) if(visit[j]==0&&low[j]>map[pos][j]) low[j]=map[pos][j]; } return sum;}double S(point a,point b)//两坐标之间距离{ double len; len=sqrt(1.0*(a.x-b.x)*(a.x-b.x)+1.0*(a.y-b.y)*(a.y-b.y)); return len;}int main(){ int t; scanf("%d",&t); while(t--) { scanf("%d",&n); init(); for(int i=0;i<n;i++) scanf("%d%d",&s[i].x,&s[i].y); for(int i=0;i<n;i++) for(int j=i+1;j<n;j++) { double len=S(s[i],s[j]); if(len>=10&&len<=1000) map[i][j]=map[j][i]=len*100; } double ans=prim(); if(ans==-1) printf("oh!\n"); else printf("%.1lf\n",ans); } return 0;}
Hdu 1879 继续畅通工程
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1879
代码如下:
#include<cstdio>#include<cstring>#include<cmath>#include<algorithm>using namespace std;#define Maxint 0x3f3f3f3f#define N 110//primstruct point{int x,y,dis,f;}s[100005]; //注意s的范围int visit[N],n,low[N],map[N][N];void init(){ for(int i=0;i<N;i++) for(int j=0;j<N;j++) { if(i==j) map[i][j]=0; else map[i][j]=Maxint; }}int prim(){ int Min,sum=0; int pos,i,j; memset(visit,0,sizeof(visit)); visit[1]=1;pos=1; for(int i=1;i<=n;i++) if(i!=pos) low[i]=map[pos][i]; for(int i=1;i<n;i++) { Min=Maxint; for(int j=1;j<=n;j++) if(visit[j]==0&&low[j]<Min) { Min=low[j]; pos=j; } sum+=Min; visit[pos]=1; for(int j=1;j<=n;j++) if(visit[j]==0&&low[j]>map[pos][j]) low[j]=map[pos][j]; } return sum;}int main(){ while(scanf("%d",&n)&&n) { int a=n*(n-1)/2; init(); for(int i=0; i<a; i++) { scanf("%d%d%d%d",&s[i].x,&s[i].y,&s[i].dis,&s[i].f); if(s[i].f==1) map[s[i].x][s[i].y]=map[s[i].y][s[i].x]=0; else map[s[i].x][s[i].y]=map[s[i].y][s[i].x]=s[i].dis; } printf("%d\n",prim()); } return 0;}
Hdu 3371 Connect the Cities
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=3371
题目大意:有N个城市,M条路,并且在输完路之后,再输入K个城市群,每个城市群里有P个城市相连,这P个城市之间的花费为0,求所有城市相连的最小花费,不能全部相连输出-1.
注意:代码用G++超时,用C++ 500ms AC
代码如下:
#include<cstdio>#include<cstring>#include<cmath>#include<algorithm>using namespace std;#define Maxint 0x3f3f3f3f#define N 510int visit[N],n,low[N],map[N][N],v[N];void init(){ for(int i=1;i<=n;i++) for(int j=1;j<=n;j++) { if(i==j) map[i][j]=0; else map[i][j]=map[j][i]=Maxint; }}int prim(){ int Min,sum=0; int pos,i,j; memset(visit,0,sizeof(visit)); visit[1]=1;pos=1; for(int i=1;i<=n;i++) if(i!=pos) low[i]=map[pos][i]; for(int i=1;i<n;i++) { Min=Maxint; for(int j=1;j<=n;j++) if(visit[j]==0&&low[j]<Min) { Min=low[j]; pos=j; } if(Min==Maxint) return -1; sum+=Min; visit[pos]=1; for(int j=1;j<=n;j++) if(visit[j]==0&&low[j]>map[pos][j]) low[j]=map[pos][j]; } return sum;}int main(){ int t; scanf("%d",&t); while(t--) { int m,k,num; scanf("%d%d%d",&n,&m,&k); init(); int a,b,c; for(int i=1; i<=m; i++) { scanf("%d%d%d",&a,&b,&c); if(map[a][b]>c) map[a][b]=c,map[b][a]=c; } for(int i=1;i<=k;i++) { scanf("%d",&num); for(int j=0;j<num;j++) scanf("%d",&v[j]); for(int j=0;j<num;j++) for(int kk=j+1;kk<num;kk++) map[v[kk]][v[j]]=map[v[j]][v[kk]]=0; } printf("%d\n",prim()); } return 0;}
Hdu 3367 Pseudoforest 最大生成树
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=3367
题目大意:将所有的点相连的最大花费,但相连的图中最多只有一个环。
代码如下:
//克鲁斯卡尔#include<cstdio>#include<cstring>#include<algorithm>using namespace std;#define N 10005int f[N],visit[N];int sum;struct point{int x,y,dis;}s[100005];bool cmp(point a,point b){ return a.dis>b.dis;}void init(){ sum=0; memset(visit,0,sizeof(visit)); for(int i=0;i<N;i++) f[i]=i;}int find(int x){ if(x!=f[x]) f[x]=find(f[x]); return f[x];}void merge(point a){ int fx=find(a.x); int fy=find(a.y); if(fx==fy&&visit[fx]==0) { sum+=a.dis; visit[fx]=1; } else { if(visit[fx]==0&&visit[fy]==0) { f[fx]=fy; sum+=a.dis; } else if(visit[fx]==0||visit[fy]==0) { visit[fx]=1; visit[fy]=1; f[fx]=fy; sum+=a.dis; } }}int main(){ int n,m; while(scanf("%d%d",&n,&m)&&n+m) { init(); for(int i=0;i<m;i++) scanf("%d%d%d",&s[i].x,&s[i].y,&s[i].dis); sort(s,s+m,cmp); for(int i=0;i<m;i++) merge(s[i]); printf("%d\n",sum); } return 0;}
关于有向图的最小生成树,应该是最小树形图,会在接下来整理。。。
- 最小生成树 水题集
- 最小比例 最小生成树
- 最小生成树&&次最小生成树
- 最小生成生成树计数
- 树+最小生成树
- 最小生成树
- 最小生成树 MST
- 最小生成树Kruskal
- kruskal 最小生成树
- 最小生成树
- 最小生成树
- 最小生成树
- 最小生成树
- 最小生成树 MST
- 最小生成树问题
- 最小生成树
- 最小生成树
- 最小生成树
- phpstorm+xdebug+wamp+xpsp3 调试配置
- 多线程--生产者消费者问题(wait和notify方法)
- 简单认识什么是基于Web Service的云端应用开发
- POJ 1113 || HDU 1348: wall(凸包问题)
- 基于hadoop的网络爬虫设计1.0
- 最小生成树 水题集
- 两个类相互包含引用的问题
- PL2303芯片实现串口转usb,但是要在电脑上装上芯片的驱动
- Selector中各种状态详解
- hdu1231 最大连续子序列
- 英语在未来考试中的地位
- As programs get larger
- The preprocessor
- B. Valera and Fruits