[最小直径生成树 模板题] BZOJ 2180 最小直径生成树 & BZOJ 2182 [Spoj1479] TGK & Ural 1569 Networking the “Iset”

我不会啊
老老实实去学吧 求图的绝对中心 && 最小直径生成树 MDST
绝对重心呢 就是枚举每一条边 然后从这条边上某个坐标 到所有点的最小距离是一条折线
然后用这一组折线乱搞就好了

这里写图片描述

怎么求MDST呢 从绝对重心跑一边最短路径树就好了

#include<cstdio>
#include<cstdlib>
#include<algorithm>
#include<cstring>
using namespace std;

const int N=205;
int d[N][N],w[N][N],rk[N][N];
int n,m;

int main(){
  int iu,iv,iw;
  freopen("t.in","r",stdin);
  freopen("t.out","w",stdout);
  scanf("%d%d",&n,&m);
  for (int i=1;i<=n;i++) for (int j=1;j<=n;j++) w[i][j]=d[i][j]=1<<29;
  for (int i=1;i<=n;i++) w[i][i]=d[i][i]=0;
  for (int i=1;i<=m;i++)
    scanf("%d%d%d",&iu,&iv,&iw),w[iu][iv]=min(w[iu][iv],iw),w[iv][iu]=d[iu][iv]=d[iv][iu]=w[iu][iv];
  for (int k=1;k<=n;k++)
    for (int i=1;i<=n;i++)
      for (int j=1;j<=n;j++)
    d[i][j]=min(d[i][j],d[i][k]+d[k][j]);
  for (int i=1;i<=n;i++){
    for (int j=1;j<=n;j++) rk[i][j]=j;
    for (int j=1;j<=n;j++)
      for (int k=j+1;k<=n;k++)
    if (d[i][rk[i][j]]>d[i][rk[i][k]])
      swap(rk[i][k],rk[i][j]);
  }
  int ans=1<<30;
  for (int u=1;u<=n;u++)
    for (int v=1;v<=n;v++){
      if (u==v || w[u][v]==1<<29) continue;
      ans=min(ans,min(d[u][rk[u][n]]<<1,d[v][rk[v][n]]<<1));
      for (int last=n,i=n-1;i;i--)
    if (d[v][rk[u][i]]>d[v][rk[u][last]])
      ans=min(ans,d[u][rk[u][i]]+d[v][rk[u][last]]+w[u][v]),last=i;
    }
  printf("%d\n",ans);
  return 0;
}
#include<cstdio>
#include<cstdlib>
#include<algorithm>
#include<cstring>
using namespace std;

const int N=205;
int d[N][N],w[N][N],rk[N][N];
int n,m;

int s1,s2;

inline int Find(){
  for (int k=1;k<=n;k++)
    for (int i=1;i<=n;i++)
      for (int j=1;j<=n;j++)
    d[i][j]=min(d[i][j],d[i][k]+d[k][j]);
  for (int i=1;i<=n;i++){
    for (int j=1;j<=n;j++) rk[i][j]=j;
    for (int j=1;j<=n;j++)
      for (int k=j+1;k<=n;k++)
    if (d[i][rk[i][j]]>d[i][rk[i][k]])
      swap(rk[i][k],rk[i][j]);
  }
  int ans=1<<30;
  for (int u=1;u<=n;u++)
    for (int v=1;v<=n;v++){
      if (u==v || w[u][v]==1<<30) continue;
      if ((d[u][rk[u][n]]<<1)<ans) ans=d[u][rk[u][n]]<<1,s1=s2=u;
      if ((d[v][rk[v][n]]<<1)<ans) ans=d[v][rk[v][n]]<<1,s1=s2=v;
      for (int last=n,i=n-1;i;i--)
    if (d[v][rk[u][i]]>d[v][rk[u][last]]){
      if (d[u][rk[u][i]]+d[v][rk[u][last]]+w[u][v]<ans)
        ans=d[u][rk[u][i]]+d[v][rk[u][last]]+w[u][v],s1=u,s2=v;
      last=i;
    }
    }
  return ans;
}

int Q[N],l,r;
int dis[N],pre[N];

inline void bfs(){
  for (int i=1;i<=n;i++) dis[i]=-1;
  l=r=-1; Q[++r]=s1; dis[s1]=0;
  if (s1!=s2)
    Q[++r]=s2,dis[s2]=0,pre[s2]=s1;
  while (l<r){
    int u=Q[++l];
    for (int i=1;i<=n;i++)
      if (w[u][i]==1 && dis[i]==-1)
    dis[i]=dis[u]+1,Q[++r]=i,pre[i]=u;
  }
}

int main(){
  int iu,iv,iw;
  freopen("t.in","r",stdin);
  freopen("t.out","w",stdout);
  scanf("%d%d",&n,&m);
  for (int i=1;i<=n;i++) for (int j=1;j<=n;j++) w[i][j]=d[i][j]=1<<29;
  for (int i=1;i<=n;i++) w[i][i]=d[i][i]=0;
  for (int i=1;i<=m;i++)
    scanf("%d%d",&iu,&iv),w[iu][iv]=w[iv][iu]=d[iu][iv]=d[iv][iu]=1;
  Find(); bfs();
  for (int i=1;i<=n;i++)
    if (pre[i])
      printf("%d %d\n",i,pre[i]);
  return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值