• 动态规划:状压DP-斯坦纳树


    最小生成树是最小斯坦纳树的一种特殊情况 

    最小生成树是在给定的点集和边中寻求最短网络使所有点连通 

    而最小斯坦纳树允许在给定点外增加额外的点,使生成的最短网络开销最小

    BZOJ2595

    题意是给定一个棋盘图。告诉你景点的位置

    然后让你在一些格子上放置指定数量的志愿者使得景点之间可以连通

    问你最少需要派遣多少枚志愿者

    典型斯坦纳树问题

    令f[i][j][k]表示已经连接的景点的集合为k时,包含点a[i][j]的最小值

    集合k的引入标志着这是一种状压DP

    即以(i,j)为根时,景点集合为k时的斯坦纳树。然后有两种转移

    1.由两个子集合并得到集合k,即f[i][j][k]=f[i][j][x]+f[i][j][y]-a[i][j],x|y=k(用景点枚举子集)

    2.由根的转移得到,即f[i][j][k]=f[x][y][k]+a[i][j],其中(i,j)和(x,y)相邻(最短路直接SPFA,同层之间的转移有环?)

      1 #include<cstdio>
      2 #include<queue>
      3 //#include<iostream>
      4 using namespace std;
      5 const int INF=100000000;
      6 const int maxn=15;
      7 const int maxm=15;
      8 int n,m,K;
      9 int bin[25];
     10 bool inq[maxn][maxm],vis[maxn][maxm];
     11 int a[maxn][maxm];
     12 int f[maxn][maxm][1024];
     13 int dx[4]={0,0,1,-1};
     14 int dy[4]={1,-1,0,0};
     15 queue<pair<int,int> > q;
     16 struct Data
     17 {
     18     int fit,sed,thd;
     19 }pre[maxn][maxm][1024];
     20 inline int read()
     21 {
     22     int x=0;char ch=getchar();
     23     while(ch>'9'||ch<'0') ch=getchar();
     24     while(ch>='0'&&ch<='9') {x=x*10+ch-'0';ch=getchar();}
     25     return x;
     26 }
     27 void spfa(int sta)
     28 {
     29     //cout<<"###"<<sta<<endl;
     30     while(!q.empty())
     31     {
     32         int x=q.front().first,y=q.front().second;
     33         inq[x][y]=0;q.pop();
     34         //cout<<x<<" "<<y<<endl;
     35         for(int k=0;k<4;k++)
     36         {
     37             int nx=x+dx[k],ny=y+dy[k];
     38             if(x<1||y<1||x>n||y>m) continue;
     39             if(f[nx][ny][sta]>f[x][y][sta]+a[nx][ny])
     40             {
     41                 f[nx][ny][sta]=f[x][y][sta]+a[nx][ny];
     42                 pre[nx][ny][sta]=(Data){x,y,sta};
     43                 if(!inq[nx][ny])
     44                 {
     45                     q.push(make_pair(nx,ny));
     46                     inq[nx][ny]=1;
     47                 }
     48             }
     49         }
     50     }
     51 }
     52 void dfs(int x,int y,int sta)
     53 {
     54     if(x>INF||pre[x][y][sta].thd==0) return;
     55     vis[x][y]=1;
     56     Data t=pre[x][y][sta];
     57     dfs(t.fit,t.sed,t.thd);
     58     if(t.fit==x&&t.sed==y) dfs(x,y,sta-t.thd);
     59 }
     60 int main()
     61 {
     62     bin[0]=1;
     63     for(int i=1;i<20;i++) bin[i]=bin[i-1]<<1;
     64     n=read();m=read();
     65     for(int i=1;i<=n;i++)
     66         for(int j=1;j<=m;j++)
     67         {
     68             a[i][j]=read();
     69             if(a[i][j]==0) K++;
     70         }
     71     //令f[i][j][k]表示已经连接的景点的集合为k时
     72     //包含点a[i][j]的最小值
     73     for(int i=1;i<=n;i++)
     74         for(int j=1;j<=m;j++)
     75             for(int k=0;k<bin[K];k++) 
     76                 f[i][j][k]=pre[i][j][k].fit=INF;
     77     K=0;
     78     for(int i=1;i<=n;i++)
     79         for(int j=1;j<=m;j++)
     80             if(a[i][j]==0)
     81                 f[i][j][bin[K]]=0,K++;
     82     //最初始是one-hot,集合中只有自己景点
     83     for(int sta=1;sta<bin[K];sta++)
     84     {
     85          for(int i=1;i<=n;i++)
     86          {
     87              for(int j=1;j<=m;j++)
     88              {
     89                 for(int s=sta&(sta-1);s;s=sta&(s-1))
     90                 {
     91                     int t=f[i][j][s]+f[i][j][sta-s]-a[i][j];
     92                     if(t<f[i][j][sta])
     93                     {
     94                         f[i][j][sta]=t;
     95                         pre[i][j][sta]=(Data){i,j,s};
     96                     }
     97                 }
     98                 if(f[i][j][sta]<INF)
     99                     q.push(make_pair(i,j)),inq[i][j]=1;
    100             }
    101         }
    102         spfa(sta);
    103     }
    104     int x,y;
    105     for(int i=1;i<=n;i++)
    106         for(int j=1;j<=m;j++)
    107             if(a[i][j]==0)
    108             {
    109                 x=i;y=j;break;
    110             }
    111     dfs(x,y,bin[K]-1);
    112     printf("%d
    ",f[x][y][bin[K]-1]);
    113     for(int i=1;i<=n;i++)
    114     {
    115         for(int j=1;j<=m;j++)
    116         {
    117             if(a[i][j]==0) printf("x");
    118             else if(vis[i][j]) printf("o");
    119             else printf("_");
    120         }
    121         puts("");
    122     }
    123     return 0;
    124 }

    这个题写完之后有一种莫名的打击感

  • 相关阅读:
    洛谷 P1934 封印
    洛谷 P2426 删数
    洛谷 P3399 丝绸之路
    SQL SERVER镜像配置,无法将 ALTER DATABASE 命令发送到远程服务器实例的解决办法
    Step7:SQL Server 多实例下的复制
    Step6:SQL Server 数据变更时间戳(timestamp)在复制中的运用
    Step5:SQL Server 跨网段(跨机房)FTP复制
    Step4:SQL Server 跨网段(跨机房)复制
    Step3 SQL Server 通过备份文件初始化复制
    Step2:SQL Server 复制事务发布
  • 原文地址:https://www.cnblogs.com/aininot260/p/9466995.html
Copyright © 2020-2023  润新知