【最小生成树】图论复习(三)
2012-07-13 16:48
183 查看
最小生成树就两种算法。一种Prim,另一种Kruscal,因为Prim酷似Dijkstra,我又比较喜欢写Dijkstra,所以我还是经常写Prim,当然偶尔也写写Kruscal,感觉效率上要高一点。这里就主要发Kruscal吧。
毕竟处于入门阶段,做的题也不会太难,大牛直接忽略吧。
第一题,按照惯例是裸题。造路行动
Kruscal写的,没什么好说。
代码:
第三题:联络员
在裸题的基础上变了形,不过也比较简单。如果是必选渠道就在读入的时候先加入生成树,然后再做一次MST,累加出来的ans就是所求了。
代码:
也属于一道变型,判断一个图中有没有环。因为我们知道在最小生成树中必然是不存在环的,所以我们可以在读入时累加,在求出MST与累加的值比较,如果MST=累加值,那么不存在环,如果MST<累加值,说明图中存在了环,明白了这个代码就好写了,这道题是用Prim做的。
代码:
总结:最小生成树以及最短路是图论中的经典问题,NOIP也很可能考到,一定要注意灵活运用,不能太死板,要多多训练自己抽象模型的能力。
(Ps:发这么些水题出来感觉有点。。。不过也算了,人都是会慢慢成长的,大牛在最开始不也是弱菜么?我现在要努力向前!)
毕竟处于入门阶段,做的题也不会太难,大牛直接忽略吧。
第一题,按照惯例是裸题。造路行动
Kruscal写的,没什么好说。
代码:
#include<cstdio> #include<cstdlib> #include<cstring> using namespace std; const int maxn=100+10; struct edge { int left; int right; int len; bool flag; }edges[maxn]; int f[maxn]; int n,k; int cmp(const void *a,const void *b) { return (*(edge *)a).len - (*(edge *)b).len; } void init() { freopen("rqnoj370.in","r",stdin); freopen("rqnoj370.out","w",stdout); } int find(int x) { if(f[x]==x)return x; f[x]=find(f[x]); return f[x]; } void merge(int u,int v) { int fu=find(u); int fv=find(v); if(fu!=fv)f[fu]=fv; } void predoing() { for(int i=1;i<=n;i++) f[i]=i; } void readdata() { scanf("%d%d",&n,&k); predoing(); for(int i=1;i<=k;i++) { scanf("%d%d%d",&edges[i].left,&edges[i].right,&edges[i].len); } } bool query(int a,int b) { if(find(a)!=find(b))return true; return false; } void solve() { int ans=0; int haveput=1; int i=1; qsort(&edges[1],k,sizeof(edges[0]),cmp); while(haveput < n) { if(query(edges[i].left,edges[i].right)) { edges[i].flag=true; merge(edges[i].left,edges[i].right); haveput++; } i++; } for(int i=1;i<=k;i++) { if(edges[i].flag==false) { ans+=edges[i].len; } } printf("%d",ans); } int main() { init(); readdata(); solve(); return 0; }
第三题:联络员
在裸题的基础上变了形,不过也比较简单。如果是必选渠道就在读入的时候先加入生成树,然后再做一次MST,累加出来的ans就是所求了。
代码:
#include<cstdio> #include<cstring> #include<cstdlib> using namespace std; const int maxn = 2000 + 10; const int maxm = 10000 + 10; struct edge { int l,r,w; }edges[maxm]; int f[maxn]; int n,m; int ans = 0; int haveput = 0; void init() { freopen("tyvj1307.in","r",stdin); freopen("tyvj1307.out","w",stdout); } int cmp(const void *a,const void *b) { return (*(edge *)a).w - (*(edge *)b).w; } int find(int x) { if(f[x] == x)return x; f[x] = find(f[x]); return f[x]; } void predoing() { for(int i = 1;i <= n;i++) { f[i] = i; } } void merge(int x,int y) { int wx = find(x); int wy = find(y); f[wx] = wy; } void readdata() { scanf("%d%d",&n,&m); predoing(); for(int i = 1;i <= m;i++) { int x,y,w,l; scanf("%d%d%d%d",&l,&edges[i].l,&edges[i].r,&edges[i].w); if(l == 1) { ans += edges[i].w; if(find(edges[i].l) != find(edges[i].r)) { merge(edges[i].l,edges[i].r); haveput++; } } } } int solve() { qsort(&edges[1],m,sizeof(edges[0]),cmp); int i = 1; while(haveput < n - 1) { if(find(edges[i].l) != find(edges[i].r)) { ans += edges[i].w; merge(edges[i].l,edges[i].r); ++haveput; } i++; } printf("%d",ans); } int main() { init(); readdata(); solve(); return 0; }最后一道:mty的宝藏
也属于一道变型,判断一个图中有没有环。因为我们知道在最小生成树中必然是不存在环的,所以我们可以在读入时累加,在求出MST与累加的值比较,如果MST=累加值,那么不存在环,如果MST<累加值,说明图中存在了环,明白了这个代码就好写了,这道题是用Prim做的。
代码:
#include<cstdio> #include<cstring> #include<queue> using namespace std; const int maxn = 1000 + 10; int map[maxn][maxn]; int dist[maxn]; bool done[maxn]; int n,com,sum; void init() { freopen("rqnoj564.in","r",stdin); freopen("rqnoj564.out","w",stdout); } void readdata() { memset(done,false,sizeof(done)); memset(dist,67,sizeof(dist)); sum = com = 0; scanf("%d",&n); for(int i = 1;i <= n;i++) for(int j = 1;j <= n;j++) { int p; scanf("%d",&p); if(p) { map[i][j] = 1; sum += 1; } } } void solve() { com = 0; typedef pair<int,int> pii; priority_queue<pii,vector<pii>,greater<pii> >q; dist[1] = 0; q.push(make_pair(dist[1],1)); for(int i = 1;i <= n;i++) { pii u = q.top(); q.pop(); while(done[u.second]) { u = q.top(); q.pop(); } int k = u.second; done[k] = true; com += dist[k]; for(int j = 1;j <= n;j++) { if(!map[k][j])continue; if(done[j])continue; if(map[k][j] < dist[j]) { dist[j] = map[k][j]; q.push(make_pair(dist[j],j)); } } } if(com == sum) printf("%c",'N'); else printf("%c",'Y'); } int main() { init(); readdata(); solve(); return 0; }
总结:最小生成树以及最短路是图论中的经典问题,NOIP也很可能考到,一定要注意灵活运用,不能太死板,要多多训练自己抽象模型的能力。
(Ps:发这么些水题出来感觉有点。。。不过也算了,人都是会慢慢成长的,大牛在最开始不也是弱菜么?我现在要努力向前!)
相关文章推荐
- (复习)图论--最小生成树--Kruskal算法
- (复习)图论--最小生成树--Prim算法
- UVa10397_Connect the Campus(最小生成树)(小白书图论专题)
- 图论 之 最小生成树 (Kruskal and Prim)
- UVa10369/POJ2349_Arctic Network(最小生成树)(小白书图论专题)
- 图论算法之最小生成树
- HOJ Tangled in Cables 图论 最小生成树 prim
- 复杂网络(2)--图论的基本理论-最小生成树问题
- 1002 搭桥-最小生成树 图论
- 图论(五)------最小生成树
- 图论, 1.各种方案的最短路径,最小生成树,拓扑排序, 2.隐式图的搜索,N-皇后问题,数独,马踏棋盘,中文划分,回文划分.
- 模板整理: 图论---最小生成树
- 「图论」最小生成树-Prime算法
- 「图论」最小生成树-kruskal算法
- 【图论】最小生成树之prim算法与kruskal算法
- 【图论06】最小生成树 1002 畅通工程
- 图论总结,查分约束系统讲解,最短路,最小生成树,二分图
- NYOJ-38 布线问题(图论,最小生成树,Prime)
- 【图论】【最小生成树】【kruskal+prime】
- 图论中的最小生成树算法