您的位置:首页 > 其它

hdu 4126(prim+树形dp)

2013-06-09 09:20 399 查看
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4126

思路:我们可以先求最小生成树,对于最小生成树的每一条边,我们要找到它的最佳替代边,使其价值最小。

具体实践方法:

假设两个各自连通的部分分别为树A,树B,dp[i][j]表示树A中的点i到树B(点j所在的树的最近距离),这个很容易用dfs实现,然后通过求出的dp[i][j],再用一个dfs求出树B到树A的最近距离(就是枚举树A中的所有点 到 树B的最近距离,取其中的最小值),这个求出来的值其实就是我们要求的最佳替代边,将它保存到一个数组中即可。总的时间复杂度为O(n^2)。

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<vector>
using namespace  std;
#define MAXN 3030
#define inf  1000000000
typedef __int64 LL;
vector<int>edge[MAXN];
int map[MAXN][MAXN];
int lowcost[MAXN];
int nearvex[MAXN];
int n,m,q;
LL sumweight;
int dp[MAXN][MAXN];//树A中的i点到树B中的点j的最近距离
int mindist[MAXN][MAXN];//保存最佳替换边
bool mark[MAXN];

void Prim(int u0)
{
memset(mark,false,(n+2)*sizeof(int));
for(int i=1;i<n;i++){
lowcost[i]=map[u0][i];
nearvex[i]=u0;
}
mark[u0]=true;
lowcost[u0]=inf;
nearvex[u0]=-1;
sumweight=0;
for(int i=0;i<n-1;i++)
{
int min=inf,v=-1;
for(int j=1;j<n;j++){
if(!mark[j]&&lowcost[j]<min){
v=j,min=lowcost[j];
}
}
sumweight+=lowcost[v];
mark[v]=true;
if(v!=-1)
{
edge[v].push_back(nearvex[v]);
edge[nearvex[v]].push_back(v);
for(int j=1;j<n;j++)
{
if(!mark[j]&&map[v][j]<lowcost[j]){
lowcost[j]=map[v][j];
nearvex[j]=v;
}
}
}
}
}

int dfs1(int u,int father,int rt)
{
for(int i=0;i<edge[u].size();i++){
int v=edge[u][i];
if(v==father)continue;
dp[rt][u]=min(dp[rt][u],dfs1(v,u,rt));
}
if(father!=rt)dp[rt][u]=min(dp[rt][u],map[rt][u]);
return dp[rt][u];
}

int dfs2(int u,int father,int rt)
{
int ans=dp[u][rt];
for(int i=0;i<edge[u].size();i++){
int v=edge[u][i];
if(v==father)continue;
ans=min(ans,dfs2(v,u,rt));
}
return ans;
}

void Solve()
{
int u,v,w;
scanf("%d",&q);
double ans=0;
// for(int i=0;i<n;i++)printf("%d***\n",nearvex[i]);
for(int i=1;i<=q;i++)
{
scanf("%d%d%d",&u,&v,&w);
if(nearvex[u]!=v&&nearvex[v]!=u){
ans+=sumweight*1.0;
}else {
ans+=sumweight*1.0-map[u][v]+min(mindist[u][v],w);
}
}
printf("%.4lf\n",ans/q);
}

int main()
{
int u,v,w;
while(scanf("%d%d",&n,&m),(n+m))
{
for(int i=0;i<n;i++)edge[i].clear();
for(int i=0;i<n;i++)
for(int j=0;j<n;j++)
map[i][j]=dp[i][j]=inf;
for(int i=0;i<m;i++){
scanf("%d%d%d",&u,&v,&w);
map[u][v]=map[v][u]=w;
}
Prim(0);
for(int i=0;i<n;i++)
dfs1(i,-1,i);
for(int i=0;i<n;i++){
for(int j=0;j<edge[i].size();j++)
{
int v=edge[i][j];
mindist[i][v]=mindist[v][i]=dfs2(v,i,i);
}
}
Solve();
}
return 0;
}


View Code
ps:hdoj上G++能过,但不知C++为何就过不了呢。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: