Uva 10462 Is There A Second Way Left? Kruskal求次小生成树
来源:互联网 发布:淘宝手机拍照技巧集锦 编辑:程序博客网 时间:2024/06/08 01:50
这两天做了三题次小生成树包括上篇博客都是用Prim算法写的;孤陋寡闻的我还以为smst就是用prim求;
直到碰到这题,很裸的次小生成树!但和以往都不一样的是它会有重边!
这样以来用prim算法考虑的话,used[ i ][ j ]数组就无法做标记;在删除边的时候也不知道怎么删除。
于是我想了一个办法来解决它。
设一个结构体
struct node{ int v[maxn];//重边的值 int cnt;//该重边的数量 int flag;//是否有重边 int flag1;}mark[maxn][maxn];
特意用来处理重边问题;mp[i][j]只要保存的是重边中最小的那条就不影响MST的求值;只要在算SMST的时候把重边考虑进去就行了。
结果……XJB胡写了162行代码,代码太丑,WA了N次,也不知道哪有问题;
/* ***********************************************Author :angon************************************************ */#include <stdio.h>#include <string.h>#include <iostream>#include <algorithm>#include <stack>#include <vector>#include <queue>#include <set>#include <map>#include <string>#include <math.h>#include <stdlib.h>#include <time.h>using namespace std;#define REP(i,k,n) for(int i=k;i<n;i++)#define REPP(i,k,n) for(int i=k;i<=n;i++)#define scan(d) scanf("%d",&d)#define scann(n,m) scanf("%d%d",&n,&m)#define LL long long#define maxn 210#define N 100000000int mp[maxn][maxn];int used[maxn][maxn];int Max[maxn][maxn];int vis[maxn],lowc[maxn],pre[maxn];int m,n;struct node{ int v[maxn]; int cnt; int flag; int flag1;}mark[maxn][maxn];int Prim(){ memset(Max,0,sizeof(Max)); memset(used,0,sizeof(used)); memset(vis,0,sizeof(vis)); for(int i=0;i<=n;i++) { pre[i]=1; lowc[i]=mp[1][i]; } lowc[1]=0; vis[1]=1; pre[1]= -1; int ans=0; for(int i=2;i<=n;i++) { int minc=N,p=-1; for(int j=1;j<=n;j++) if(!vis[j] && lowc[j]<minc) { minc=lowc[j]; p=j; } if(minc==N) return -1; ans+=minc; vis[p]=1; used[p][pre[p]]=used[pre[p]][p]=1; for(int j=1;j<=n;j++) { if(vis[j] && j!=p) Max[p][j]=Max[j][p]=max(Max[j][pre[p]],lowc[p]); if(!vis[j] && mp[p][j] < lowc[j]) { lowc[j]=mp[p][j]; pre[j]=p; } } } return ans;}int f[maxn][maxn];int smst(){ int minc=N,ans=Prim(); for(int i=1;i<=n;i++) for(int j=i+1;j<=n;j++) { if(mark[i][j].flag && used[i][j]) { for(int k=0;k<mark[i][j].cnt;k++) if(k!=f[i][j]) minc=min(minc,ans+mark[i][j].v[k]-mp[i][j]); } if(mp[i][j]!=N && !used[i][j]) minc=min(minc,ans+mp[i][j]-Max[i][j]); } if(minc==N) return -1; return minc;}int main(){ int t,ca=1; scan(t); while(t--) { int u,v,w; scanf("%d%d",&n,&m); for(int i=1;i<=n;i++) for(int j=i+1;j<=n;j++) { mp[i][j]=mp[j][i]=N; f[i][j]=f[j][i]=0; mark[i][j].flag=mark[j][i].flag=0; mark[i][j].flag1=mark[j][i].flag1=0; mark[i][j].cnt=mark[j][i].cnt=1; } while(m--) { scanf("%d%d%d",&u,&v,&w); if(mark[u][v].flag1) { mark[u][v].flag=1; int k = mark[u][v].cnt++; // printf("k=%d\n",k); mark[u][v].v[k]=w; if(mp[u][v]>w) { f[u][v]=f[v][u]=k; mp[u][v] = mp[v][u] = w; } continue; } mp[u][v]=mp[v][u]=w; mark[u][v].v[0]=mark[v][u].v[0]=w; mark[u][v].flag1=mark[v][u].flag1=1; } // printf("f=%d\n",f); // for(int i=0;i<mark[4][5].cnt;i++) // printf("%d\n",mark[4][5].v[i]); // printf("mp=%d\n",mp[4][5]); int ans1=Prim(); printf("Case #%d : ",ca++); if(ans1==-1) { printf("No way\n"); continue; } // printf("ans1=%d\n",ans1); int ans2=smst(); if(ans2==-1) printf("No second way\n"); else printf("%d\n",ans2); } return 0;}
百度一下,原来重边用kruskal算法是极好的;又学到了。确是是这样,prim算法有点两两枚举点的感觉,与点的关系比较密切,而kruskal则是从边出发;当边有重边,再枚举点已不合适,从边出发非常符合常理。
kruskal求次小生成树和prim算法求 的核心思想应该说是一致的,都是先求出MST,再通过删除MST上的一条边,构造新的生成树;枚举所有的边,得出答案。Prim时间复杂度 O(V*V); kruskal时间复杂度 O(V*E);(自己分析的,应该没错吧0-0)
最终AC代码:
/* ***********************************************Author :angon************************************************ */#include <stdio.h>#include <string.h>#include <iostream>#include <algorithm>#include <stack>#include <vector>#include <queue>#include <set>#include <map>#include <string>#include <math.h>#include <stdlib.h>#include <time.h>using namespace std;#define REP(i,k,n) for(int i=k;i<n;i++)#define REPP(i,k,n) for(int i=k;i<=n;i++)#define scan(d) scanf("%d",&d)#define scann(n,m) scanf("%d%d",&n,&m)#define LL long long#define maxn 222#define INF 1000000struct Edge{ int u,v,w;}edge[maxn];bool cmp(Edge n1,Edge n2){ return n1.w<n2.w;}int p[maxn],used[maxn];int find(int x){ if(x==p[x]) return x; return p[x]=find(p[x]);}int main(){ // freopen("out.txt","w",stdout); int t,n,m,ca=1; scan(t); while(t--) { scann(n,m); REP(i,0,m) scanf("%d%d%d",&edge[i].u,&edge[i].v,&edge[i].w); sort(edge,edge+m,cmp); REPP(i,0,n) p[i]=i; int ans=0,cnt=0; REP(i,0,m) { int u=edge[i].u; int v=edge[i].v; int t1=find(u); int t2=find(v); if(t1!=t2) { ans+=edge[i].w; p[t1]=t2; used[cnt++]=i; } if(cnt==n-1) break; } printf("Case #%d : ",ca++); if(cnt < n-1) { printf("No way\n"); continue; } /*求次小生成树*/ if(m==n-1) { printf("No second way\n"); continue; } int ans2=INF; //printf("cnt=%d\n",cnt); REP(i,0,cnt) { REPP(j,0,n) p[j]=j; int smst=0,ct=0; REP(j,0,m) { if(j==used[i]) //轮流删除MST中的一条边求S_MST continue; int u=edge[j].u; int v=edge[j].v; int t1=find(u); int t2=find(v); if(t1!=t2) { smst += edge[j].w; p[t1]=t2; ct++; } if(ct==n-1) break; } if(ct==n-1) ans2=min(ans2,smst); } if(ans2==INF) printf("No second way\n"); else printf("%d\n",ans2); } return 0;}
0 0
- Uva 10462 Is There A Second Way Left? Kruskal求次小生成树
- Is There A Second Way Left? (UVA 10462)【kruskal 求次小生成树存在】
- UVa 10462 Is There A Second Way Left? (Kruskal,次小生成树)
- Uva 10462 Is There A Second Way Left? (次小生成树)
- UVA - 10462 Is There A Second Way Left?(次小生成树)
- UVA 10462 Is There A Second Way Left?(Kruskal算法/Prim算法)
- UVA 10462 Is There A Second Way Left?
- UVA-10462-Is There A Second Way Left? (次小生成树带重边)
- UVA10462-Is There A Second Way Left?
- Is There A Second Way Left?
- uva10462 Is There A Second Way Left? (次小生成树)
- UVA10462_Is There A Second Way Left? _kruskal的次小生成树
- Where there is a will,there is a way...
- Where there is a will, there is a way
- where there is internet ,there is a way
- If There Is Only One Solution, Get a Second Opinion
- 一些强大的Shell命令(Where there is a shell,there is a way!)
- Is there a way to customize Android default tabs
- 高仿今日头条顶部渐变滚动条
- SQL语句大全
- shell 之16进制的数据显示方式
- 后台传过来的JSON数据里的date传到前台的时候显示的是【Object object】 处理方法
- Android之ListView优化
- Uva 10462 Is There A Second Way Left? Kruskal求次小生成树
- nyoj 114某种序列《乘,加》
- Eclipse新建Servlet时候,不会自动生成mapping到web.xml,而是在代码中加入注解@WebServlet
- 字符串操作
- mysql必知必会--建表语句
- win10 与ubuntu14.04.4 LTS双系统时间不统一解决
- js获取url中的查询参数
- 招商银行个人网银专业版 v7.2.6
- MFC OnIdle函数学习