<span style="font-size:14px;">原题链接:</span>
http://acm.hust.edu.cn/vjudge/problem/viewProblem.action?id=11062
http://poj.org/problem?id=1639
参考资料:
http://blog.csdn.net/ji414341055/article/details/5781800
http://www.cnblogs.com/vongang/archive/2012/07/03/2575383.htmlhttp://blog.sina.com.cn/s/blog_64675f540100sd8m.html
【思考】{以下不讨论原题,讨论等于K度限制时}
①:如果没有K限制的话,就算你是个233也知道这是个最小生成树=(*@ο@*)=;【什么你居然看不出来(滑稽
②:加了K限制,就有问题了:就是让你生成一棵最小生成树,并且一个点的度为K。
【③(滑稽:什么你看出来这是一道拉板题????【我做时还不知道有板子(这是实话
③:我们把这个东西叫做【度限制最小生成树】(百度拉板不解释
【算法实现】{以下不讨论原题,讨论等于K度限制时}
以下将被限制的点记作0点,其余为1~n,共n+1个点。
①忽视0点的存在。剩下的是一片森林,你可以得到许多连通块,记有m个。
②对于每一个连通块,造一棵最小生成树。
③然后你可以发现,0点到每一个连通块有许多条边,对于每一个连通块,取权值最小的与0点相连。这样我们得到了m度的最小生成树。
④如果m>k,则无解,因为不可能使0点的度小于m。
⑤【以下由m度求m+1度】对于每一条不在生成树内但与0点相连的边,连接后必定有一个环。取环中权值最大但与0点毫无关系的边删除,这样我们可以得到一棵m+1度的树。
⑥为了保证这棵m+1度生成树是最小的,我们要枚举所有不在生成树内但与0点相连的边,取这些树中最小的树。这样一棵m+1度的最小生成树就完成了。
⑦重复⑤⑥,直至m==k时,就造好了一棵k度的最小生成树。
【2333】{让我们回到原题}
题目有我们求小于等于K度。首先我们看到可以看到我们有方法造出m度至k度的最小生成树,取其中最小的一棵输出就好了。
上代码:{POJ 1639}
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <windows.h>
#include <string>
#include <map>
using namespace std;
int n,m,kk,ans,nn,mm,p[200100][2],fa[1010],f[1005][1005];
bool g[1005][1005];
map<string,int> name;
struct poi{
int x,y,num;
} haha[200100];
struct QAQ{
int ma,pma;
} m_a[1010];
bool cmp(const poi &k,const poi &l){
return k.num<l.num;
}
int FF(int k){
while (k!=fa[k]) k=fa[k];
return k;
}
void dfs(int l,int k,int ma,int mak){
fa[k]=l;
for (int i=1;i<=n;i++)
if (i!=l&&g[i][k]){
if (f[i][k]>ma){
m_a[i].ma=f[i][k];
m_a[i].pma=i;
}
else{
m_a[i].ma=ma;
m_a[i].pma=mak;
}
dfs(k,i,m_a[i].ma,m_a[i].pma);
}
return;
}
int getname(string po){
if (name.find(po)==name.end()){
name[po]=++n;
}
return name[po];
}
int main(){
scanf("%d",&nn);m=0;int ll=0;n=0;
name["Park"]=0;
for (int i=1;i<=nn;i++){ //读入
string jj,kk;
int l;cin >> jj >> kk;
scanf("%d",&l);l++;
int j=getname(jj),k=getname(kk);
if (j>k) swap(j,k);
if (j!=0){
m++;
haha[m].x=j;haha[m].y=k;haha[m].num=l;
}
else ll++;
f[j][k]=f[j][k]==0?l:min(f[j][k],l);
f[k][j]=f[j][k];
}
scanf("%d",&kk);
sort(haha+1,haha+m+1,cmp);
for (int i=1;i<=n;i++) fa[i]=i;
memset(g,0,sizeof(g));
for (int i=1;i<=m;i++){
int k=FF(haha[i].x),l=FF(haha[i].y);
if (k==l) continue;
ans+=haha[i].num;
g[haha[i].x][haha[i].y]=1;
g[haha[i].y][haha[i].x]=1;
fa[k]=l;
//printf("%d\n",ans);
}
mm=0;
memset(p,-1,sizeof(p));
for (int i=1;i<=n;i++){
if (f[0][i]!=0&&(f[0][i]<p[FF(i)][1]||p[FF(i)][1]==-1)){
p[FF(i)][1]=f[0][i];
p[FF(i)][0]=i;
}
}
for (int i=1;i<=n;i++){
//printf("%d %d\n",p[i][0],p[i][1]);
if (p[i][1]>=0){
ans+=p[i][1];
g[0][p[i][0]]=1;
g[p[i][0]][0]=1;
mm++;
}
}
//printf("%d\n",ans);
int tot=ans;
for (int i=mm+1;i<=min(kk,ll);i++){
dfs(0,0,-1,0);//father,point,max,maxpoint
int k=1000000000,l;
for (int j=1;j<=n;j++)
if (g[0][j]==0&&f[0][j]>0&&f[0][j]-m_a[j].ma<k){
k=f[0][j]-m_a[j].ma;
l=j;
}
ans+=k;
if (ans<tot) tot=ans;
g[0][l]=1;g[l][0]=1;
g[m_a[l].pma][fa[m_a[l].pma]]=0;
g[fa[m_a[l].pma]][m_a[l].pma]=0;
//printf("%d %d\n",ans,l);
}
printf("Total miles driven: %d\n",tot-n);
system("pause");
return 0;
}