有n个巨人要去Park聚会。巨人A和先到巨人B那里去,然后和巨人B一起去Park。B君是个土豪,他家的停车场很大,可以停很多车,但是Park的停车场是比较小。只能停k辆车。现在问你在这个限制条件下。居然到达Park的最短距离-------------------------------------------------------------------------------------分割线
如果把那个条件去掉。那么就是就是求最小生成树。加上那个条件其实就是求顶点度数限制为k的最小生成树。做法
1.忽略顶点V0。我们对其他顶点做一次最小生成树,此时形成一颗森林。
2.对步骤1中形成的每一颗最小生成树离顶点最近的点连起来。此时顶点的度数为m.
3.由m度->m+1度
(1)先dp预处理出当前生成树中与顶点V0到Vi的路径中与V0不关联的权值最大的边。dp[i].d记录的是权值,dp[i].u和dp[i].v记录的是边两边的点。
(2)对于每一个不在生成树的<v0,v>把他们加进去最小生成树中,那么久会生成一个环。我们把环中的最大的权值删去。即1中得到的dp[v].d。就会形成m+1个度
(3)对于(2)中我们枚举每一个顶点v。当minnum=min(g[v0][v]-dp[v].d)最小的时候。点v就是所求的点。 (4)重复步骤(3)直到k。其实当某一步的minnum>=0的时候就可以停止算法了。因为就算在增加度数生成树的权值也不会减小
#include<stdio.h>
#include<string.h>
#include<iostream>
#include<algorithm>
#include<map>
#include<set>
#include<vector>
using namespace std;
const int INF=0x3f3f3f3f;
const int maxn=22;
struct Edge
{
int u,v,d;
Edge (){}
Edge(int a,int b,int c):u(a),v(b),d(c){}
bool operator <(const Edge &e) const{
return d<e.d;}
};
int n,m,k;
int cnt;
int ans;
int parent[maxn];
map<string,int>nodes;
vector<Edge>edges;
int g[maxn][maxn];
bool tree[maxn][maxn];
int minEdge[maxn];
Edge dp[maxn];
int find(int p)
{
if(p==parent[p])
return parent[p];
return parent[p]=find(parent[p]);
}
void un(int p,int q)
{
parent[find(p)]=find(q);
}
void kruskal()
{
sort(edges.begin(),edges.end());
for(int i=0;i<edges.size();i++)
{
int p=edges[i].u;
int q=edges[i].v;
if(p==1||q==1)
continue;
if(find(p)!=find(q))
{
un(p,q);
tree[p][q]=tree[q][p]=1;
ans+=edges[i].d;
}
}
}
void dfs(int cur,int pre)
{
for(int i=2;i<=cnt;i++)
{
if(i==pre||!tree[cur][i])
continue;
if(dp[i].d==-1)
{
if(dp[cur].d>g[cur][i])
dp[i]=dp[cur];
else
{
dp[i].u=cur;
dp[i].v=i;
dp[i].d=g[cur][i];
}
}
dfs(i,cur);
}
}
void slove()
{
int keyPoint[maxn];
//memset(keyPoint,0,sizeof(keyPoint));
for(int i=2;i<=cnt;i++)
{
if(g[1][i]!=INF)
{
int color=find(i);
if(minEdge[color]>g[1][i])
{
minEdge[color]=g[1][i];
keyPoint[color]=i;
}
}
}
for(int i=1;i<=cnt;i++)
{
if(minEdge[i]!=INF)
{
m++;
tree[1][keyPoint[i]]=tree[keyPoint[i]][1]=1;
ans+=g[1][keyPoint[i]];
}
}
for(int i=m+1;i<=k;i++)
{
memset(dp,-1,sizeof(dp));
dp[1].d=-INF;
for(int j=2;j<=cnt;j++)
if(tree[1][j])
dp[j].d=-INF;
dfs(1,-1);
int idx,minnum=INF;
for(int j=2;j<=cnt;j++)
{
if(minnum>g[1][j]-dp[j].d)
{
minnum=g[1][j]-dp[j].d;
idx=j;
}
}
if(minnum>=0)
break;
tree[1][idx]=tree[idx][1]=1;
tree[dp[idx].u][dp[idx].v]=tree[dp[idx].v][dp[idx].u]=1;
ans+=minnum;
}
}
void init()
{
memset(g,INF,sizeof(g));
memset(tree,0,sizeof(tree));
memset(minEdge,INF,sizeof(minEdge));
m=0;
cnt=1;
ans=0;
nodes["Park"]=1;
for(int i=0;i<maxn;i++)
parent[i]=i;
}
int main()
{
scanf("%d",&n);
string s1,s2;
int d;
init();
for(int i=1;i<=n;i++)
{
cin>>s1>>s2>>d;
if(!nodes[s1])
nodes[s1]=++cnt;
if(!nodes[s2])
nodes[s2]=++cnt;
int u=nodes[s1];
int v=nodes[s2];
edges.push_back(Edge(u,v,d));
g[u][v]=g[v][u]=min(g[u][v],d);
}
scanf("%d",&k);
kruskal();
slove();
printf("Total miles driven: %d\n",ans);
return 0;
}