zoukankan      html  css  js  c++  java
  • 斯坦纳树

    两种转移:

    f[x][s] 在点x,当前关键点的连通状态为S

    子集合并 f[x][s]=f[x][s']+f[x][s-s'] 出现圈

    求出s这一层后,最优可以去更新其他的点 f[x][s]=f[y][s]+dis(x,y) 常用spfa

    这样就求出了某些点连同的连通块,直接求出的就是最小生成树

    题目:

    BZOJ2595: [Wc2008]游览计划

    就是裸斯坦纳树,但需要记录一下路径

    #include<bits/stdc++.h>
    using namespace std;
    #define p(x,y) x*m+y+1
    int read(){
      int x=0,f=1;char ch=getchar();
      while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
      while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
      return x*f;
    }
    #define N 15
    #define inf 1e9
    int n,m,f[N][N][1030],a[N][N];
    bool vis[N*N],an[N][N];
    struct point{
      int x,y;
    };
    int h[]={-1,0,1,0};
    int l[]={0,-1,0,1};
    queue<point> q;
    struct From{
      int x,y,now;
    }from[N][N][1030];
    void spfa(int noww){
      while(!q.empty()){
        point now=q.front();vis[p(now.x,now.y)]=0;q.pop();
        for(int i=0;i<4;i++){
          int x=now.x+h[i];
          int y=now.y+l[i];
          if(x<0||y<0||x>=n||y>=m)continue;
          if(f[x][y][noww]>f[now.x][now.y][noww]+a[x][y]){
            f[x][y][noww]=f[now.x][now.y][noww]+a[x][y];
            from[x][y][noww].x=now.x;from[x][y][noww].y=now.y;from[x][y][noww].now=noww;
            if(!vis[p(x,y)])vis[p(x,y)]=1,q.push(point{x,y});
          }
        }
      }
    }
    void dfs(int x,int y,int now){
      if(!from[x][y][now].now)return;
      an[x][y]=1;
      dfs(from[x][y][now].x,from[x][y][now].y,from[x][y][now].now);
      if(from[x][y][now].x==x&&from[x][y][now].y==y)dfs(x,y,now^from[x][y][now].now);
    }
    int main(){
      n=read();m=read();
      memset(f,127,sizeof(f));
      int K=0;
      for(int i=0;i<n;i++)
        for(int j=0;j<m;j++){
          a[i][j]=read();
          if(a[i][j]==0){
            f[i][j][1<<K]=0;K++;
          }
        }
      int Max_s=(1<<K);
      for(int sta=1,tmp;sta<Max_s;sta++){
        for(int i=0;i<n;i++)
          for(int j=0;j<m;j++){
            for(int s=sta&(sta-1);s;s=(s-1)&sta){
              if(f[i][j][sta]>f[i][j][s]+f[i][j][sta-s]-a[i][j]){
                f[i][j][sta]=f[i][j][s]+f[i][j][sta-s]-a[i][j];
                from[i][j][sta].x=i;from[i][j][sta].y=j;from[i][j][sta].now=s;
              }
            }
            if(f[i][j][sta]<inf){vis[p(i,j)]=1;q.push(point{i,j});}
          }
        spfa(sta);
      }
      int x,y;
      for(int i=0;i<n;i++)
        for(int j=0;j<m;j++)
          if(!a[i][j]){x=i;y=j;break;}
      printf("%d
    ",f[x][y][Max_s-1]);
      dfs(x,y,Max_s-1);
      for(int i=0;i<n;i++){
        for(int j=0;j<m;j++)
          if(!a[i][j])putchar('x');
          else if(an[i][j])putchar('o');
          else putchar('_');
        puts("");
      }
      return 0;
    }
    
    

    (2)模拟赛题目

    求对应点对连通的最小权值和,点对个数<=4

    先裸的斯坦纳树跑一遍

    因为只要求对应的点对连通,所以两个点对之间可能不联通。所以在简单dp一下,求出答案。

  • 相关阅读:
    硬盘
    vim 使用技巧
    R语言自定义函数中的位置参数、关键字参数、默认参数
    R语言中批量加载函数
    R语言中如何在函数内部定义全局变量
    centos7.9中安装dnf;bash: dnf: command not found...
    ubantu中实现root用户登录ssh
    linux系统中如何修改主机名
    Ubuntu 20.04.2如何root登录
    清北学堂模拟day6 兔子
  • 原文地址:https://www.cnblogs.com/wjyi/p/5633460.html
Copyright © 2011-2022 走看看