(专题)最小生成树

来源:互联网 发布:淘宝开店买衣服 编辑:程序博客网 时间:2024/06/06 07:21

最小生成树:kruskal和prim

kruskal:

首先对所有边按权值进行排序,依次选一条短的边,如果加入这条边且不能构成环,就把他加入到最小树里,怎么判断能不能构成环呢,可以把已经连通好了的点归为同一个集合里,每次加边的时候看这两点是否在一个集合里,不在一个集合里则这条边可加,因此可以用并查集来实现,时间复杂度为:(n个点,m条边,O(MlogM+MlogN),因为M一般比N大,所以为O(MlogM);

prim

首先任取一点入树。用一个数组来记录已生成的树到那些未加入树的顶点的距离,每次通过这个数组找离树最近的点,把这个点入树,然后通过这个点松弛其他为入树的点到新树的距离,在找最近点,在松弛,一直到把所有点都入树即可。借助堆优化,可以将复杂度降低到O(MlogN),下面分享一个自己写的裸的优先队列优化的prim

#include<stdio.h>#include<vector>#include<queue>#include<algorithm>#include<string.h>using namespace std;int prim();int build();struct node{int ri,qu;bool operator<(const node &a)const{return qu>a.qu;}};vector<node>w[1000];int n,m,book[1000];priority_queue<node>q;int main(){int a,b,c;while(~scanf("%d %d",&n,&m)){for(int i=0;i<=n;i++)w[i].clear();while(!q.empty()){q.pop();}memset(book,0,sizeof(book));for(int i=0;i<m;i++){scanf("%d %d %d",&a,&b,&c);node t;t.qu=c;t.ri=b;w[a].push_back(t);t.ri=a;w[b].push_back(t);}printf("%d\n",prim());}}int build(){node t;book[1]=1;for(int i=0;i<w[1].size();i++){t=w[1].at(i);q.push(t);}return 0;}int prim(){int ans=1,sum=0;build();node re,pe;while(!q.empty()&&ans<n){re=q.top();q.pop();if(book[re.ri])continue;sum+=re.qu;ans++;book[re.ri]=1;for(int i=0;i<w[re.ri].size();i++){pe=w[re.ri].at(i);if(book[pe.ri])continue;q.push(pe);//printf("ha%d\n",pe.qu);}//printf("%d %d %d %d\n",re.ri,sum,ans,q.empty());}return sum;}

注意理解prim和dijikstra的区别:prim每次找离已生成的树集合最近的点,后者是找离原点最近的点,所以用数组dis来记录生成树到各个顶点的距离,也就是我们要记录的这个距离,并非为这个点到原点的最短距离,而是到任意一个已经入树的树顶点的最短距离。





Borg Maze
Time Limit: 1000MS Memory Limit: 65536KTotal Submissions: 13547 Accepted: 4414

Description

The Borg is an immensely powerful race of enhanced humanoids from the delta quadrant of the galaxy. The Borg collective is the term used to describe the group consciousness of the Borg civilization. Each Borg individual is linked to the collective by a sophisticated subspace network that insures each member is given constant supervision and guidance. 

Your task is to help the Borg (yes, really) by developing a program which helps the Borg to estimate the minimal cost of scanning a maze for the assimilation of aliens hiding in the maze, by moving in north, west, east, and south steps. The tricky thing is that the beginning of the search is conducted by a large group of over 100 individuals. Whenever an alien is assimilated, or at the beginning of the search, the group may split in two or more groups (but their consciousness is still collective.). The cost of searching a maze is definied as the total distance covered by all the groups involved in the search together. That is, if the original group walks five steps, then splits into two groups each walking three steps, the total distance is 11=5+3+3.

Input

On the first line of input there is one integer, N <= 50, giving the number of test cases in the input. Each test case starts with a line containg two integers x, y such that 1 <= x,y <= 50. After this, y lines follow, each which x characters. For each character, a space `` '' stands for an open space, a hash mark ``#'' stands for an obstructing wall, the capital letter ``A'' stand for an alien, and the capital letter ``S'' stands for the start of the search. The perimeter of the maze is always closed, i.e., there is no way to get out from the coordinate of the ``S''. At most 100 aliens are present in the maze, and everyone is reachable.

Output

For every test case, output one line containing the minimal cost of a succesful search of the maze leaving no aliens alive.

Sample Input

26 5##### #A#A### # A##S  ####### 7 7#####  #AAA####    A## S ####     ##AAA########  

Sample Output

811

Source

Svenskt Mästerskap i Programmering/Norgesmesterskapet 2001
大体题意是从S出发,要访问所有的A点,问最少步数,其中可以你访问的时候可以分成好几个小队分别访问,在S和A的地方可以分。

仔细想想其实就是最小生成树的题,只不过刚开始不确定每个点之间的权值;

两个思路,都要用bfs,第一个是先bfs找到每个点之间的权值,然后在最小生成树

第二种是prim,每次用bfs来找理他最近的那个点

#include<stdio.h>#include<queue>#include<string.h>using namespace std;int book[200][200],n,m,tree[200][200];char map[200][200];int go[4][2]={1,0,-1,0,0,1,0,-1};struct node{int x,y,step;}pe,re;int check(node tt){if(tt.x<0||tt.x>=n||tt.y<0||tt.y>=m||book[tt.x][tt.y]||map[tt.x][tt.y]=='#')return 1;return 0;}node bfs(node px){queue<node>q;while(!q.empty()){q.pop();}memset(book,0,sizeof(book));book[px.x][px.y]=1;pe=px;q.push(pe);while(!q.empty()){pe=q.front();q.pop();for(int i=0;i<4;i++){re=pe;re.x+=go[i][0];re.y+=go[i][1];re.step++;if(check(re))continue;if(map[re.x][re.y]=='A'){return re;}q.push(re);book[re.x][re.y]=1;}}}int main(){int i,j,K,k,num,bookk[500];long long int sum;char c;node t,index[500],min,minn[500];scanf("%d",&K);while(K--){memset(tree,0,sizeof(tree));memset(bookk,0,sizeof(bookk));sum=0;k=0,num=0;scanf("%d %d",&m,&n);getchar();//while(c!='\n'){//c=getchar();//}for(i=0;i<n;i++){gets(map[i]);}for(i=0;i<n;i++){for(j=0;j<m;j++){if(map[i][j]=='S'||map[i][j]=='A'){if(map[i][j]=='S')map[i][j]='A';index[k].x=i;index[k].y=j;index[k].step=0;tree[i][j]=k;k++;}}}num=k;for(i=0;i<num;i++)minn[i]=index[i];for(i=0;i<num;i++){if(i==0){//tree[k++]=index[i];bookk[i]=1;map[index[i].x][index[i].y]=' ';}else{min.step=2501;for(j=0;j<num;j++){if(bookk[j]==0)continue;if(map[minn[j].x][minn[j].y]!='A'){minn[j]=bfs(index[j]);}if(minn[j].step<min.step)min=minn[j];}//tree[k]=min;//tree[k++].step=0;bookk[tree[min.x][min.y]]=1;sum+=min.step;map[min.x][min.y]=' ';//printf("%d %d %d\n",min.x,min.y,min.step);}}printf("%lld\n",sum);}return 0;}





The Unique MST
Time Limit: 1000MS Memory Limit: 10000KTotal Submissions: 28824 Accepted: 10292

Description

Given a connected undirected graph, tell if its minimum spanning tree is unique. 

Definition 1 (Spanning Tree): Consider a connected, undirected graph G = (V, E). A spanning tree of G is a subgraph of G, say T = (V', E'), with the following properties: 
1. V' = V. 
2. T is connected and acyclic. 

Definition 2 (Minimum Spanning Tree): Consider an edge-weighted, connected, undirected graph G = (V, E). The minimum spanning tree T = (V, E') of G is the spanning tree that has the smallest total cost. The total cost of T means the sum of the weights on all the edges in E'. 

Input

The first line contains a single integer t (1 <= t <= 20), the number of test cases. Each case represents a graph. It begins with a line containing two integers n and m (1 <= n <= 100), the number of nodes and edges. Each of the following m lines contains a triple (xi, yi, wi), indicating that xi and yi are connected by an edge with weight = wi. For any two nodes, there is at most one edge connecting them.

Output

For each input, if the MST is unique, print the total cost of it, or otherwise print the string 'Not Unique!'.

Sample Input

23 31 2 12 3 23 1 34 41 2 22 3 23 4 24 1 2

Sample Output

3Not Unique!

Source

POJ Monthly--2004.06.27 srbga@POJ
次小生成树裸题

当时还不知道次小生成树,理解题意后,想着是应该先生成一颗最小树,把树上的边记录下来,暴力每次不用已知生成树里的一条边,然后在生成一颗最小树,看和已知最小树大小一不一样;

做完听某k君说还有更高效的方法, 


下面是我的比较笨的方法:

#include<stdio.h>#include<vector>#include<algorithm>#include<string.h>using namespace std;int f[200],ans,sum,sum1;struct node{int le,ri,cost;};void init(int n){ans=0;sum1=0;for(int i=0;i<=n;i++)f[i]=i;return;}int find(int x){if(x==f[x])return x;return f[x]=find(f[x]);}int merge(int a,int b){int t1,t2;t1=find(a);t2=find(b);if(t1!=t2){f[t1]=t2;return 1;}return 0;}int cmp(node a,node b){return a.cost<b.cost;}int main(){int n,m,i,map[200][200],j,k,flog;node t;node index[200]; vector<node>q;scanf("%d",&k);while(k--){memset(map,0,sizeof(map));scanf("%d %d",&n,&m);flog=0;sum=0;init(n);q.clear();for(i=0;i<m;i++){scanf("%d %d %d",&t.le,&t.ri,&t.cost);q.push_back(t);}sort(q.begin(),q.end(),cmp);for(i=0;i<q.size();i++){t=q.at(i);if(merge(t.le,t.ri)){sum+=t.cost;index[ans++]=t;//map[t.le][t.ri]=map[t.ri][t.le]=t.cost;}if(ans==n-1)break;}for(j=0;j<n-1;j++){init(n);for(i=0;i<q.size();i++){t=q.at(i);if(index[j].le==t.le&&index[j].ri==t.ri||index[j].le==t.ri&&index[j].ri==t.le){continue;}if(merge(t.le,t.ri)){ans++;sum1+=t.cost;}if(ans==n-1)break;}if(sum1==sum){flog=1;break;}}if(flog){printf("Not Unique!\n");}else{printf("%d\n",sum);}}return 0;}


k度限制生成树:待补~~~!!!

0 0