您的位置:首页 > 其它

hdu 4756 MST+树形dp ****

2015-09-01 17:28 330 查看
题意:给你n(n = 1000)个二维点,第一个点是power plant,还有n - 1个点是dormitories。然后现在知道有一条寝室到寝室的边是不能连的,但是我们不知道是哪条边,问这种情况下,最小生成树的最大值。

好题,毕竟做了一下午,注意dis要double转换

dfs求的是从cur点出发到以u为根的树的最小距离

#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstring>
#include<cmath>
#include<queue>
#include<map>
using namespace std;
#define MOD 1000000007
const int INF=0x3f3f3f3f;
const double eps=1e-5;
typedef long long ll;
#define cl(a) memset(a,0,sizeof(a))
#define ts printf("*****\n");
const int MAXN=1005;
int n,m,tt;
/*
* Kruskal算法求MST
*/
const int MAXM=10000000;//最大边数
int tol;//边数,加边前赋值为0
struct Edge
{
int to,next;
}edge[MAXM];
int head[MAXN],tot;
void init()
{
tot = 0;
memset(head,-1,sizeof(head));
}
void addedge(int u,int v)
{
edge[tot].to = v; edge[tot].next = head[u];
head[u] = tot++;
}
bool mp[MAXN][MAXN];
double dp[MAXN][MAXN];
/*
* Prim求MST
* 耗费矩阵cost[][],标号从0开始,0~n-1
* 返回最小生成树的权值,返回-1表示原图不连通
*/
int vis[MAXN];
double lowc[MAXN];
double Prim(double cost[][MAXN],int n)//点是0~n-1
{
double ans=0;
memset(vis,false,sizeof(vis));
vis[0]=-1;
int last[MAXN];
last[0]=0;
for(int i=1;i<n;i++)lowc[i]=cost[0][i];
for(int i=1;i<n;i++)
{
double minc=INF;
int p=-1;
for(int j=0;j<n;j++)
if(vis[j]!=-1&&minc>lowc[j])
{
minc=lowc[j];
p=j;
}
if(minc==INF)return -1;//原图不连通
mp[vis[p]][p]=mp[p][vis[p]]=1;
addedge(vis[p],p);
addedge(p,vis[p]);
ans+=minc;
vis[p]=-1;
for(int j=0;j<n;j++)
if(vis[j]!=-1&&lowc[j]>cost[p][j])
{
vis[j]=p;
lowc[j]=cost[p][j];
}
}
return ans;
}
int x[MAXN],y[MAXN];
double dist[MAXN][MAXN];
double dis(int i,int j)
{
return sqrt((double)(x[i]-x[j])*(double)(x[i]-x[j])+(double)(y[i]-y[j])*(double)(y[i]-y[j]));
}
double dfs(int cur,int u,int fa){
double res=(double)INF;
for(int i=head[u];i!=-1;i=edge[i].next){
int v=edge[i].to;
if(v==fa)continue;
double tmp=dfs(cur,v,u);
dp[u][v]=dp[v][u]=min(tmp,dp[u][v]);
res=min(res,tmp);
}
if(fa!=cur){
res=min(res,dist[cur][u]);
}
return res;
}
int main()
{
int i,j,k,ca=1;
#ifndef ONLINE_JUDGE
freopen("1.in","r",stdin);
#endif
scanf("%d",&tt);
int val;
while(tt--)
{
init();
tol=0;
scanf("%d%d",&n,&val);
cl(dist);
for(i=0;i<n;i++)
{
scanf("%d%d",x+i,y+i);
}
for(i=0;i<n;i++)
{
for(j=0;j<n;j++)
{
dist[i][j]=dist[j][i]=dis(i,j);
}
}
cl(mp);
double sumw=Prim(dist,n);
double Max=sumw;
for(int i=0;i<n;i++)
for(int j=i;j<n;j++)
dp[i][j]=dp[j][i]=(double)INF;
for(i=0;i<n;i++)
{
dfs(i,i,-1);
}
for(i=1;i<n;i++)  //枚举每条边
{
for(j=i+1;j<n;j++)
{
if(mp[i][j])    Max=max(Max,sumw-dist[i][j]+dp[i][j]);
}
}
printf("%.2lf\n",Max*val);
}
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: