セカンダリ生成ツリーprimとkruskal
prim:まずprimで最小生成ツリーTを求め、primと同時に、Tに任意の2点u,vを結ぶ唯一の路の中で重み値が最大の辺の重み値を1つのマトリクスmaxd[u][v]で記録することは容易である.primはノードとその親ノードを1つ増加するたびに、DPを採用すると、最大重み値は新たに加わった辺であるか、親ノードから開始点までのDPで算出される距離であるか.すなわち、maxd[j][p]=max[p][j]=lowc[p]>max[j][closest[p]?lowc[p] : max[j][closest[p]] ; Tにないすべてのエッジuvを列挙し,エッジuvを加えると必ずmaxd[u][v]のエッジに置き換えられ,これによりセカンダリが保証される.
あと一歩列挙しますが、ここでは書きません.
kruskal:最小ツリーを複数回求める:まず、kruskalで最小生成ツリーを求め、visit配列で最小生成ツリーのエッジを記録し、合計numバーと仮定した後、最小生成ツリーnum回をループし、毎回最初に求めた最小生成ツリーのエッジ仮定を使わない:最初に最小生成ツリーを求めるには1、2、4の3つのエッジを用い、合計5つのエッジを用い、そのサイクルが3回の場合,それぞれ1,2,4を用いずに最小生成木のMSTを求め,最小のMSTは次小生成木である.
const int INF=0x3f3f3f3f;
const int MAXN=110;
bool vis[MAXN],used[MAXN][MAXN];
int lowc[MAXN],closest[MAXN],maxd[MAXN][MAXN];
int Prim(int cost[][MAXN],int n)// 0~n-1
{
int ans=0;
memset(vis,false,sizeof(vis));
vis[0]=true;
lowc[0]=0;
for(int i=1; i
{
lowc[i]=cost[0][i];//
closest[i]=1;
}
for(int i=1; i
{
int minc=INF;
int p=-1;
for(int j=0; j
if(!vis[j]&&minc>lowc[j])
{
minc=lowc[j];
p=j;
}
if(minc==INF)return -1;//
ans+=minc;
vis[p]=true;//p
used[p][closest[p]]=used[closest[p]][p]=true;
for(int j=0; j
{
///
if(vis[j]&&j!=p)
{
maxd[j][p] = maxd[p][j] = lowc[p] > maxd[j][closest[p]] ? lowc[p] : maxd[j][closest[p]] ;
}
if(!vis[j]&&lowc[j]>cost[p][j])
{
lowc[j]=cost[p][j];//p
closest[j]=p;
}
}
}
return ans;
}
あと一歩列挙しますが、ここでは書きません.
kruskal:最小ツリーを複数回求める:まず、kruskalで最小生成ツリーを求め、visit配列で最小生成ツリーのエッジを記録し、合計numバーと仮定した後、最小生成ツリーnum回をループし、毎回最初に求めた最小生成ツリーのエッジ仮定を使わない:最初に最小生成ツリーを求めるには1、2、4の3つのエッジを用い、合計5つのエッジを用い、そのサイクルが3回の場合,それぞれ1,2,4を用いずに最小生成木のMSTを求め,最小のMSTは次小生成木である.
#include
#include
#include
#include
using namespace std;
#define M 99999999
int n, m,w;
int f[10005], sum, cou;
int visit[10005];
struct edge
{
int u;
int v;
int w;
};
edge e[10005];
void init()
{
int i;
for (i = 1; i <= n; i++)
{
f[i] = i;
}
}
int cmp(edge a, edge b)
{
return a.wint getf(int v)
{
if (f[v] == v)
return v;
else
{
f[v] = getf(f[v]);
return f[v];
}
}
int merg(int v, int u)
{
int t1, t2;
t1 = getf(v);
t2 = getf(u);
if (t1 != t2)
{
f[t2] = t1;
return 1;
}
return 0;
}
int mintree()
{
int i,flag;
init();
flag = 0;
w = 0;
cou = 0;
for (i = 1; i <= m; i++)
{
if (merg(e[i].v, e[i].u))
{
cou++;
visit[w++] = i;
}
if (cou == n - 1)
{
flag = 1;
break;
}
}
//cout << sum << endl;
return flag ;
}
///
int cimintree()
{
int j, flag,min;
min = M;
for (int i = 0; i < w; i++)
{
flag = 0;
init();
cou = 0;
sum = 0;
for (j = 1; j <= m; j++)
{
if (j != visit[i])
{
if (merg(e[j].v, e[j].u))
{
cou++;
sum = sum + e[j].w;
}
if (cou == n - 1)
{
flag = 1;
break;
}
}
}
if (flag&&sum < min) min = sum;
}
min = (min == M) ? -1 : min;
return min;
}
int main()
{
int i,flag,min;
while (scanf("%d %d", &n,&m) != EOF)
{
if (n == 0)
break;
sum = 0;
cou = 0;
memset(e, 0, sizeof(e));
memset(f, 0, sizeof(f));
for (i = 1; i <= m; i++)
{
scanf("%d %d %d", &e[i].u, &e[i].v, &e[i].w);
}
sort(e + 1, e + m + 1, cmp);
flag = mintree();
if (flag == 0)
{
cout << "-1" << endl;
}
else
{
min = cimintree();
cout << min << endl;
}
}
return 0;
}