次小生成树
原理:相当于找出 最小生成树上的最大值, 然后用 不属于最小生成树上的边 去替换(肯定比最小生成树小) , 取最小的那个就是次小生成树
题目链接:
http://poj.org/problem?id=1679
分析:
果的次小生成树,直接水过,细节搞错了,,,无语的纠结了一下
代码
#include <cstring>
#include <cstdio>
#include <iostream>
#include <algorithm>
#include <queue>
#include <vector>
using namespace std;
#define maxn 150
int dp[maxn][maxn];//这样可以快速找到上次保存的最大值,并与现在的值比较
int statu[maxn][maxn];
int map[maxn][maxn];
int n , m;
int dis[maxn];
int vis[maxn];
int pre[maxn];
int mTree;
void prim()
{
memset(vis,0,sizeof(vis));
memset(pre,0,sizeof(pre));
for( int i = 1 ; i <= n ; ++i )
dis[i] = map[1][i] , pre[i] = 1 ;
vis[1] = 1;
while(1)
{
int mm = 1e9 ;
int mi = 0;
for(int i = 2 ; i <= n ; ++i)
if( !vis[i]&&dis[i] < mm )mm = dis[mi=i];
if( mi == 0 )break;
mTree += mm;
vis[mi] = 1;
statu[mi][pre[mi]] = statu[pre[mi]][mi] = -1;
for(int i = 1 ; i <= n ; ++i)
if(vis[i])
dp[i][mi] = dp[mi][i] = max(dp[pre[i]][i] , mm);//这里要顾及 最小生成树的每个点,将它的置为最大值
for(int i = 1 ; i <= n ; ++i)
{
if( !vis[i] && dis[i] > map[mi][i] )
{
dis[i] = map[mi][i];
pre[i] = mi;
}
}
}
}
void deal()
{
int Min = 1e9;
for(int i = 1 ; i <= n ; ++i)
{
for(int j = i + 1 ; j <= n ; ++j)
{
if( statu[i][j] == 1 )
{
Min = min(Min,mTree + map[i][j] - dp[i][j]);
}
}
}
if(Min == mTree )printf("Not Unique!\n");
else printf("%d\n",mTree);
}
void solve( )
{
prim();
deal();
}
void init()
{
mTree = 0;
for(int i = 0 ; i <= n ; ++i)
for(int j = 0 ; j <= n ; ++j)
map[i][j] = 1e9;
memset(dp,0,sizeof(dp));
memset(statu,0,sizeof(statu));
}
int main()
{
int T;
cin >> T;
while(T-- && cin >> n >> m )
{
init();
for(int i = 0 ; i < m ; ++i)
{
int a, b , c;
cin >> a >> b >> c;
map[a][b] = map[b][a] = c;
statu[a][b] = statu[b][a] = 1;
}
solve();
}
}