Time Limit: 1000MS | Memory Limit: 10000K | |
Total Submissions: 20293 | Accepted: 7124 |
Description
Input
Output
Sample Input
2 3 3 1 2 1 2 3 2 3 1 3 4 4 1 2 2 2 3 2 3 4 2 4 1 2
Sample Output
3 Not Unique!
Source
次小生成树问题,看了我好久,感觉还是差那么一点点啊,看了好多大神的博客,自己重写了一下,终于过了,思路还不是很清晰啊,prim算法中运用的dp的思想,对dp还是不怎么懂啊,下阶段要好好看看dp,krusal的次小生成树还没怎么看懂,还是要多做题;
参考了博客http://blog.csdn.net/jarily/article/details/8912538
直接把其中的算法介绍部分转过来啦,还是要多看几遍
这里面的用了一个path数组储存两点中权值最大的那条路径;
low数组保存边的权值;
用pre数组保存前驱的位置,用一个uesd数组标记是否在生成树中;
#include <cstdio> #include <cstring> #define max(a,b) ((a)>(b)?(a):(b)) #define min(a,b) ((a)<(b)?(a):(b)) const int maxn=100+5; const int INF=0x3fffffff; int map[maxn][maxn],low[maxn]; int path[maxn][maxn],pre[maxn];//从i到j的路径上最大边的权值 int visit[maxn],used[maxn][maxn];//标记数组 int n,m; int prim() { int i,j,pos,mst=0; memset(visit,0,sizeof(visit));//初始化 memset(path,0,sizeof(path)); memset(used,0,sizeof(used)); visit[1]=1; for(i=1;i<=n;i++) { low[i]=map[1][i]; pre[i]=1;//记录前驱 } for(i=1;i<n;i++) { pos=-1; for(j=1;j<=n;j++) { if(!visit[j]&&(pos==-1||low[j]<low[pos])) pos=j; } used[pos][pre[pos]]=used[pre[pos]][pos]=1;//标记已经加入生成树 mst+=map[pos][pre[pos]];//权值相加 visit[pos]=1; for(j=1;j<=n;j++) { if(visit[j]&&j!=pos) path[pos][j]=path[j][pos]=max(path[j][pre[pos]],low[pos]);//求从pos到j权值最大的路径 if(!visit[j]&&low[j]>map[pos][j]) { low[j]=map[pos][j];//更新low数组 pre[j]=pos; } } } return mst; } int main() { int t,x,y,w,i,j; scanf("%d",&t); while(t--) { scanf("%d%d",&n,&m); for(i=1;i<=n;i++) for(j=1;j<=n;j++) map[i][j]=INF;//把map初始化为INF for(i=1;i<=m;i++) { scanf("%d%d%d",&x,&y,&w); map[x][y]=map[y][x]=w; } int mst; int res=INF; mst=prim(); for(i=1;i<=n;i++) for(j=1;j<=n;j++) { if(i!=j&& !used[i][j]) res=min(res,mst+map[i][j]-path[i][j]);//生成次小生成树 } if(res==mst) puts("Not Unique!"); else printf("%d\n",mst); } return 0; }如果生成的次小生成树和最小生成树相等说明不唯一,不相等说明唯一;
最小生成树中加入一条边,再删除最小生成树中的一条边,就得到次小生成树,这里主要进行了预处理,对权值较大的路径进行预处理。
这个博客的次小生成树讲的不错 http://www.cnblogs.com/hxsyl/p/3290832.html
kruskal待更新;