pku1639
这题郁闷啊,手抄prayer的模板都抄不对~~~
#include<iostream>
#include
<algorithm>
#include
<cstring>
#include
<map>
#include
<stdio.h>
#include
<string>
#define N1 110
using namespace std;
int const INF=100000000;
int cost[N1][N1];//花费 = 边
int used[N1][N1];//表示这条边是否在生成树中
int father[N1];//生成树中点的父节点
int maxlen[N1];//表示i点到根路径上除了与根直接相连的边外,边权最大的边权
int vis[N1];//标记
int d[N1]; //求最小生成树时的最小生成树代价
int AnsMst;//当前m度生成树的代价
int N, degree, lim;//degree表示最小限度,lim表示限度值
int g[N1][N1];//生成树中的儿子关系,正向表
map<stringint> mat;
void MST(int S) //求从S点开始的最小生成树
{
    
while(1){
        
int K=-1;
        
for(int i=1; i<=N; i++){
            
if(!vis[i] && d[i]!=INF && (K==-1||d[K]>d[i]))
                K
=i;
        }
        
if(K==-1break;
        vis[K]
=1;
        AnsMst
+=d[K];
        g[father[K]][
++g[father[K]][0]]=K;//记录儿子
        if(d[K]!=0) maxlen[K] = max(maxlen[father[K]], d[K]);//算边权最大的边
        used[K][father[K]] = used[father[K]][K] = 1;//标记边在生成树中
        for(int i=1; i<=N; i++){
            
if(!vis[i] && cost[K][i]<d[i]){
                father[i]
=K;
                d[i]
=cost[K][i];
            }
        }
    }
}
void Build()
{
    
for(int i=1; i<=N; i++)
        father[i]
=i;
    
for(int i=1; i<=N; i++)
        d[i]
=INF;
    
for (int i = 1; i <= N; i++)
        
for (int j = 1; j <= N; j++)
        used[i][j] 
= 0;//所有的边都在生成树外
    for(int i=1; i<=N; i++)
        g[i][
0]=0//儿子数全为0
    for (int i = 1; i <= N; i++) vis[i] = 0// 标记清空
    vis[1]=1;
    degree
=0;
    maxlen[
1]=-INF; //根的maxlen为-INF;
    AnsMst=0//开始时生成树的代价为0
    while(1){
        
int K=-1;
        
for(int i=1; i<=N; i++){
            
if(!vis[i] && (K==-1 ||cost[1][i]<cost[1][K]))
                K
=i; //找个距根边权最小的点开始做最小生成树
        }
        
if(K==-1break;
        father[K]
=1//father 为 1
        maxlen[K]=-INF; //maxlen[k]=--INF;
        d[K]=0;
        degree
++;//连通分支个数加1
        AnsMst+=cost[1][K]; //生成树代价增加

        MST(K);
    }
}
void Init()//开始的输入处理
{
    mat.clear();
    mat[
"Park"]=1;
    N
=1;
    
int M;
    scanf(
"%d"&M);
    
for(int i=1; i<=30; i++)
        
for(int j=1; j<=30; j++)
            cost[i][j]
=INF;
    
while(M--){
        
string a, b;
        
int c;
        cin
>>a>>b>>c;
        
int ida, idb;
        
if(mat.find(a)==mat.end()) mat[a]=++N, ida=N;
        
else ida=mat[a];
        
if(mat.find(b)==mat.end()) mat[b]=++N, idb=N;
        
else idb=mat[b];
        cost[ida][idb]
=cost[idb][ida]=c;
    }

    scanf(
"%d"&lim);
}
void Dfs(int nod, int fa) //更新维护maxlen和生成树中的父子关系
{
    father[nod]
=fa;
    vis[nod]
=1;
    
if(fa==1) maxlen[nod]=-INF;
    
else
        maxlen[nod]
=max(maxlen[fa], cost[nod][fa]);
    
for(int i=1; i<=g[nod][0]; i++)
        
if(used[nod][g[nod][i]]&&!vis[g[nod][i]])
            Dfs(g[nod][i], nod);
}
void Solve(){
    
if(degree>lim)
        printf(
"Error\n");
    
int ans=AnsMst;
    
while(degree<lim){
        degree
++;
        
int id=-1;
        
int delta=INF;
        
for(int i=1; i<=N; i++){//找代价最小的进行扩张
            if(cost[1][i]!=INF && !used[1][i]){
                
if(id==-1){
                    id
=i;
                    delta
=cost[1][i]-maxlen[i];
                    
continue;
                }
                
if(cost[1][i]-maxlen[i]<delta){
                    id
=i;
                    delta
=cost[1][i]-maxlen[i];
                }
            }
        }
        
if(id==-1){ break;}
        AnsMst
+=delta;//加上delta值
        ans=min(ans, AnsMst);
        
int Len=maxlen[id];
        used[
1][id]=used[id][1]=1;//表示边被加入到当前的生成树中
        g[1][++g[1][0]]=id; //表示根多加了一个儿子
        while(cost[id][father[id]]!=Len){//找最大的边,并顺路维护儿子关系
            int fa=father[id];
            g[id][
++g[id][0]]=fa;
            id
=fa;
        }
        used[id][father[id]]
=used[father[id]][id]=0;//标记边被删去
        for(int i=1; i<=N; i++)
            vis[i]
=0;
        Dfs(
11);//维护
    }
    printf(
"Total miles driven: %d\n", ans);
}
int main()
{
    Init();
    Build();
    Solve();

    
return 0;
}