一、.思路
设限制结点为des.
1. 求去掉des的最小生成树,此时求出来的是最小生成森林
2.添加des到各连通分量的边,当然取最小的边。
3.此时得到m度的生成树,我们要求的是小于等于k度的最小生成树,此时我们可以用来调整的边只有k-m条,
注意我们不一定要强制添加k-m条从des出发的边,并删除与其构成环的最大的边,而是如果在可调整的范围内(满足度限制要求<=k)已经是最小的生成树
就可以直接退出。
这里给出算法的主过程,方便大家理解!
思路参考:国家集训队论文《最小生成树问题的拓展》
代码参考:http://www.cnblogs.com/ylfdrib/archive/2010/08/21/1805505.html
http://happylch21.blog.163.com/blog/static/16563975920113224491211/
int kDegreeMinTree()
{
int cost=0;
cost+=kruscal();
int m;
cost+=mDegreeMinTree(m);
cost+=expandToKDegree(k-m);
return cost;
}
二、.代码
#include<cstdio>
#include<iostream>
using namespace std;
// freopen("data.in","r",stdin);
#include<algorithm>
#include<cstring>
#define N 25
#define M N*N//double
#define MAX 1000000000
struct Edge
{
int u,v,next;
int w;
} edge[M];
bool cmp(const int &a,const int &b)
{
return edge[a].w<edge[b].w;
}
struct Graph
{
int index[M],len;
int first[N];
bool branch[M];
int _V,_E,des;//!!
int k;
int father[N];//!!前后两次的含义不一样,第一次是作为并查的顶点,第二次是作为某一条边的父边
int best[N];
char brother[25][15];
char t[15];
void initial(int m)
{
_V=0;
_E=0;
memset(first,-1,sizeof(first));
}
int find()
{
for(int i=0; i<_V; i++)
{
if(strcmp(brother[i],t)==0)return i;
}
strcpy(brother[_V],t);//!!
return _V++;
}
void createGraph(int m)
{
initial(m);
while(m--)
{
scanf("%s",t);
int u=find();
scanf("%s",t);
int v=find();
int w;
scanf("%d",&w);
add(u,v,w);
add(v,u,w);
}
for(int i=0; i<_V; i++)
{
if(strcmp("Park",brother[i])==0)
{
des=i;
break;
}
}
scanf("%d",&k);
}
void add(int u,int v,int w)
{
edge[_E].u=u;
edge[_E].v=v;
edge[_E].w=w;
edge[_E].next=first[u];
first[u]=_E;
_E++;
}
int findx(int u)
{
if(father[u]==u)return u;
else return father[u]=findx(father[u]);
}
void Union(int x,int y)
{
father[x]=father[y];
}
int kruscal()
{
int cost=0;
len=_E>>1;
for(int i=0; i<len; i++)index[i]=i<<1;
sort(index,index+len,cmp);
memset(branch,0,sizeof(branch));
for(int i=0; i<_V; i++)father[i]=i;
for(int i=0; i<len; i++)
{
int e=index[i],u=edge[e].u,v=edge[e].v;
if(u==des||v==des)continue;
int root1=findx(u),root2=findx(v);
if(root1!=root2)
{
branch[e]=branch[e^1]=true;
cost+=edge[e].w;
Union(root1,root2);
}
}
return cost;
}
int mDegreeMinTree(int &m)
{
m=0;
int cost=0;
while(1)
{
int minE=-1;
for(int e=first[des]; e!=-1; e=edge[e].next)
{
int v=edge[e].v;
int rootV=findx(v);
if(rootV!=des)
{
if(minE==-1||edge[minE].w>edge[e].w)minE=e;
}
}
if(minE==-1)break;
m++;
cost+=edge[minE].w;
branch[minE]=branch[minE^1]=true;
Union(findx(edge[minE].v),des);//!!
}
return cost;
}
void calFather(int u)
{
for(int e=first[u]; e!=-1; e=edge[e].next)
{
if(branch[e])
{
father[edge[e].v]=e;
branch[e]=branch[e^1]=false;
calFather(edge[e].v);
branch[e]=branch[e^1]=true;//!!恢复
}
}
}
void dfs(int u)
{
int fE=father[u],fP=edge[fE].u;
if(fP!=des)
{
int e=best[fP];
if(e==-1 || edge[fE].w>edge[e].w)best[u]=fE;
else best[u]=e;
}
for(int e=first[u]; e!=-1; e=edge[e].next)
{
if(branch[e])
{
branch[e]=branch[e^1]=false;
dfs(edge[e].v);
branch[e]=branch[e^1]=true;
}
}
}
int expandToKDegree(int rest)
{
int cost=0;
calFather(des);
while(rest)
{
memset(best,-1,sizeof(best));
for(int e=first[des]; e!=-1; e=edge[e].next)
{
int v=edge[e].v;
if(edge[father[v]].u==des)dfs(v);//!!best[v]=-1;恒立
}
int minE=-1,minCost=MAX;
for(int e=first[des]; e!=-1; e=edge[e].next)
{
if(!branch[e])
{
int v=edge[e].v;
int curCost=edge[e].w-edge[best[v]].w;
if(curCost<0&&minCost>curCost)//!!
{
minCost=curCost;
minE=e;
}
}
}
if(minE==-1)return cost;
else
{
int v=edge[minE].v;
int other=best[v];
cost+=minCost;
branch[minE]=branch[minE^1]=true;
branch[other]=branch[other^1]=false;
calFather(v);//!!
rest--;
}
}
return cost;
}
int kDegreeMinTree()
{
int cost=0;
cost+=kruscal();
int m;
cost+=mDegreeMinTree(m);
cost+=expandToKDegree(k-m);
return cost;
}
void printTree()
{
for(int e=0; e<_E; e+=2)
{
if(branch[e])cout<<edge[e].u<<' '<<edge[e].v<<' '<<edge[e].w<<endl;
}
cout<<endl;
}
void printEdge(int *a,char *s)
{
printf("%s\n",s);
for(int u=0; u<_V; u++)
{
cout<<u<<' '<<endl;
int e=a[u];
cout<<edge[e].u<<' '<<edge[e].v<<' '<<edge[e].w<<endl;
}
cout<<endl;
}
} net;
int main()
{
// freopen("data.in","r",stdin);
int m;
cin>>m;
net.createGraph(m);
printf("Total miles driven: %d\n",net.kDegreeMinTree());
return 0;
}