一、.思路
設限制結點爲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;
}