poj1639

有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; 
}



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值