zoukankan      html  css  js  c++  java
  • bzoj 4006 管道连接 —— 斯坦纳树+状压DP

    题目:https://www.lydsy.com/JudgeOnline/problem.php?id=4006

    用斯坦纳树求出所有关键点的各种连通情况的代价,把这个作为状压(压的是集合选择情况)的初值DP即可。

    代码如下:

    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #include<vector>
    #include<queue>
    #define pb push_back
    using namespace std;
    int rd()
    {
      int ret=0,f=1; char ch=getchar();
      while(ch<'0'||ch>'9'){if(ch=='-')f=0; ch=getchar();}
      while(ch>='0'&&ch<='9')ret=ret*10+ch-'0',ch=getchar();
      return f?ret:-ret;
    }
    int const xn=1005,xm=6005,xxn=(1<<10)+5,inf=0x3f3f3f3f;
    int n,m,hd[xn],ct,to[xm],nxt[xm],w[xm],f[xn][xxn],g[xxn];
    int c[15],bin[15],cnt;
    bool vis[xn];
    queue<int>q;
    vector<int>v[15];
    int Min(int x,int y){return x<y?x:y;}
    void add(int x,int y,int z){to[++ct]=y; nxt[ct]=hd[x]; hd[x]=ct; w[ct]=z;}
    void spfa(int sta)
    {
      memset(vis,0,sizeof vis);
      for(int i=1;i<=n;i++)if(f[i][sta]<inf)q.push(i),vis[i]=1;
      while(q.size())
        {
          int x=q.front(); q.pop(); vis[x]=0;
          for(int i=hd[x],u;i;i=nxt[i])
        if(f[u=to[i]][sta]>f[x][sta]+w[i])
          {
            f[u][sta]=f[x][sta]+w[i];
            if(!vis[u])vis[u]=1,q.push(u);
          }
        }
    }
    int main()
    {
      bin[0]=1; for(int i=1;i<=10;i++)bin[i]=bin[i-1]*2;
      n=rd(); m=rd(); int K=rd();
      for(int i=1,x,y,z;i<=m;i++)
        x=rd(),y=rd(),z=rd(),add(x,y,z),add(y,x,z);
      memset(f,0x3f,sizeof f);
      for(int i=1,cr,x;i<=K;i++)
        {
          cr=rd(); x=rd();
          if(!c[cr])c[cr]=++cnt;
          v[c[cr]].pb(i); f[x][bin[i-1]]=0;//i!
        }
      int mx=bin[K];
      for(int sta=1;sta<mx;sta++)
        {
          for(int i=1;i<=n;i++)
        for(int s=(sta&(sta-1));s;s=(sta&(s-1)))
          f[i][sta]=Min(f[i][sta],f[i][s]+f[i][sta^s]);
          spfa(sta);
        }
      memset(g,0x3f,sizeof g); mx=bin[cnt];
      for(int sta=1;sta<mx;sta++)
        {
          int s=0;
          for(int j=1;j<=cnt;j++)
        if(sta&bin[j-1]){for(int k=0;k<v[j].size();k++)s|=bin[v[j][k]-1];}
          for(int j=1;j<=n;j++)g[sta]=Min(g[sta],f[j][s]);
        }
      for(int sta=1;sta<mx;sta++)
        for(int s=(sta&(sta-1));s;s=(sta&(s-1)))
          g[sta]=Min(g[sta],g[s]+g[sta^s]);
      printf("%d
    ",g[mx-1]);
      return 0;
    }
  • 相关阅读:
    docker 方式安装gitlab时,项目的clone地址及项目文件列表地址为机器名的问题解决办法
    CPU流水线
    Element中el-form嵌套el-table双击编辑提交检验
    java基础知识
    C#多线程下载
    mysql优化
    C++ 算法(一)
    前端vue 的面试总结 以及答案以及前端技术点面试
    C# 组合任务
    C# List去重DistinctBy扩展
  • 原文地址:https://www.cnblogs.com/Zinn/p/10235994.html
Copyright © 2011-2022 走看看