两个题次小生成树的扩展题。
先prim求出最小生成树,枚举删除每条树边后求分割成的两部分之间的最小连接费用,这一步用一个O(n^2)的n遍dfs求解。
不过HDU 4756这个题我被sqrt函数卡死,之前的写法HDU被卡爆栈,給sqrt传负数爆栈
//double tmp=(double)(x[i]-x[j])*(x[i]-x[j])+(y[i]-y[j])*(y[i]-y[j]);
dis[i][j]=dis[j][i]=sqrt(tmp);
HDU 4756
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
#define N 1010
#define INF 0x3f3f3f3f
using namespace std;
int n,k;
int x[N],y[N];
double dis[N][N];
double d[N];
int vis[N];
bool mp[N][N];
double ans;
struct Edge{
int v,next;
}edge[N*2];
int head[N],cnt;
double dp[N][N];
void init(){
memset(head,-1,sizeof(head));
cnt=0;
}
void addedge(int u,int v){
edge[cnt].v=v;
edge[cnt].next=head[u];
head[u]=cnt++;
edge[cnt].v=u;
edge[cnt].next=head[v];
head[v]=cnt++;
}
void prim(){
for(int i=0;i<n;i++){
vis[i]=0;
d[i]=dis[0][i];
}
vis[0]=-1;
ans=0;
memset(mp,0,sizeof(mp));
for(int i=1;i<n;i++){
double Min=(double)INF;
int node=-1;
for(int j=0;j<n;j++){
if(vis[j]!=-1 && d[j]<Min){
node=j;
Min=d[j];
}
}
ans+=Min;
mp[vis[node]][node]=mp[node][vis[node]]=1;
addedge(vis[node],node);
vis[node]=-1;
for(int j=0;j<n;j++){
if(vis[j]!=-1 && d[j]>dis[node][j]){
vis[j]=node;
d[j]=dis[node][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].v;
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,dis[cur][u]);
}
return res;
}
int main(){
//freopen("a.txt","r",stdin);
//freopen("b.txt","w",stdout);
int t,T;
scanf("%d",&T);
for(t=1;t<=T;t++){
scanf("%d %d",&n,&k);
for(int i=0;i<n;i++){
scanf("%d %d",&x[i],&y[i]);
}
for(int i=0;i<n;i++){
for(int j=i;j<n;j++){
double tmp=(double)(x[i]-x[j])*(double)(x[i]-x[j])+(double)(y[i]-y[j])*(double)(y[i]-y[j]);
//double tmp=(double)(x[i]-x[j])*(x[i]-x[j])+(y[i]-y[j])*(y[i]-y[j]);
dis[i][j]=dis[j][i]=sqrt(tmp);
}
}
init();
prim();
for(int i=0;i<n;i++)
for(int j=i;j<n;j++)
dp[i][j]=dp[j][i]=(double)INF;
for(int j=0;j<n;j++)
dfs(j,j,-1);
double ANS=ans; //这里一定要初始化为ans
//printf("%lf\n",ans);
for(int i=1;i<n;i++){
for(int j=i+1;j<n;j++){
if(mp[i][j]){
ANS=max(ANS,ans-dis[i][j]+dp[i][j]);
}
}
}
printf("%.2lf\n",ANS*k);
}
return 0;
}
HDU 4126
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
#define N 3010
#define INF 0x3f3f3f3f
typedef long long ll;
using namespace std;
int n,m;
int dis[N][N];
int d[N];
int vis[N];
bool mp[N][N];
ll ans;
struct Edge{
int v,next;
}edge[N*2];
int head[N],cnt;
int dp[N][N];
void init(){
memset(head,-1,sizeof(head));
cnt=0;
}
void addedge(int u,int v){
edge[cnt].v=v;
edge[cnt].next=head[u];
head[u]=cnt++;
edge[cnt].v=u;
edge[cnt].next=head[v];
head[v]=cnt++;
}
void prim(){
for(int i=0;i<n;i++){
vis[i]=0;
d[i]=dis[0][i];
}
vis[0]=-1;
ans=0;
memset(mp,0,sizeof(mp));
for(int i=1;i<n;i++){
int Min=INF;
int node=-1;
for(int j=0;j<n;j++){
if(vis[j]!=-1 && d[j]<Min){
node=j;
Min=d[j];
}
}
ans+=Min;
mp[vis[node]][node]=mp[node][vis[node]]=1;
addedge(vis[node],node);
vis[node]=-1;
for(int j=0;j<n;j++){
if(vis[j]!=-1 && d[j]>dis[node][j]){
vis[j]=node;
d[j]=dis[node][j];
}
}
}
}
int dfs(int cur,int u,int fa){
int res=INF;
for(int i=head[u];i!=-1;i=edge[i].next){
int v=edge[i].v;
if(v==fa)continue;
int 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,dis[cur][u]);
}
return res;
}
int main(){
//freopen("a.txt","r",stdin);
//freopen("b.txt","w",stdout);
int u,v,w;
while(scanf("%d %d",&n,&m)){
if(n==0 && m==0)break;
for(int i=0;i<n;i++)
for(int j=0;j<n;j++) dis[i][j]=INF;
for(int i=0;i<m;i++){
scanf("%d %d %d",&u,&v,&w);
dis[u][v]=dis[v][u]=w;
}
init();
prim();
for(int i=0;i<n;i++)
for(int j=i;j<n;j++)
dp[i][j]=dp[j][i]=INF;
for(int j=0;j<n;j++)
dfs(j,j,-1);
ll ANS=0;
//printf("%lf\n",ans);
int q;
scanf("%d",&q);
for(int i=0;i<q;i++){
scanf("%d %d %d",&u,&v,&w);
if(!mp[u][v]) ANS+=ans;
else ANS+=ans-dis[u][v]+min(w,dp[u][v]);
}
printf("%.4lf\n",(double)ANS/q);
}
return 0;
}
最小生成树扩展算法
本文介绍了一种基于Prim算法求解最小生成树后,通过深度优先搜索(DFS)寻找删除每条边后的最小连接费用的方法。该算法适用于解决特定类型的图论问题,如评估网络的鲁棒性和成本优化。
1082

被折叠的 条评论
为什么被折叠?



