zoukankan      html  css  js  c++  java
  • 洛谷4294 [WC2008]游览计划——斯坦纳树

    题目:https://www.luogu.org/problemnew/show/P4294

    大概是状压。两种转移,一个是以同一个点为中心,S由自己的子集拼起来;一个是S相同、中心不同的同层转移。

    注意S由自己的子集拼起来的时候要减去一倍的自己位置的代价。

    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #include<queue>
    using namespace std;
    int rdn()
    {
      int ret=0;bool fx=1;char ch=getchar();
      while(ch>'9'||ch<'0'){if(ch=='-')fx=0;ch=getchar();}
      while(ch>='0'&&ch<='9')ret=ret*10+ch-'0',ch=getchar();
      return fx?ret:-ret;
    }
    int Mn(int a,int b){return a<b?a:b;}
    const int N=105,M=(1<<10)+5,K=15,INF=N*(1<<16);
    int n,m,tot,bh[K][K],x[N],y[N],w[N],dp[N][M],bin[K];
    queue<int> q; bool ins[N]; int to[N][M][2][2];
    char ch[K][K];
    void cz(int k,int d,int s)
    {
      dp[d][s]=dp[k][s]+w[d];
      to[d][s][0][0]=k;to[d][s][0][1]=s;to[d][s][1][0]=to[d][s][1][1]=0;
      if(!ins[d])q.push(d),ins[d]=1;
    }
    void spfa(int s)
    {
      for(int i=1;i<=tot;i++)
        q.push(i),ins[i]=1;
      while(q.size())
        {
          int k=q.front(),d;q.pop();ins[k]=0;
          if(x[k]>1&&dp[d=bh[x[k]-1][y[k]]][s]>dp[k][s]+w[d])cz(k,d,s);
          if(x[k]<n&&dp[d=bh[x[k]+1][y[k]]][s]>dp[k][s]+w[d])cz(k,d,s);
          if(y[k]>1&&dp[d=bh[x[k]][y[k]-1]][s]>dp[k][s]+w[d])cz(k,d,s);
          if(y[k]<m&&dp[d=bh[x[k]][y[k]+1]][s]>dp[k][s]+w[d])cz(k,d,s);
        }
    }
    void solve(int cr,int s)
    {
      ch[x[cr]][y[cr]]='o';
      if(to[cr][s][0][0])solve(to[cr][s][0][0],to[cr][s][0][1]);
      if(to[cr][s][1][0])solve(to[cr][s][1][0],to[cr][s][1][1]);
    }
    int main()
    {
      n=rdn();m=rdn();int cnt=0;bin[0]=1;
      memset(dp,0x3f,sizeof dp);
      for(int i=1;i<=n;i++)
        for(int j=1;j<=m;j++)
          {
        bh[i][j]=++tot;w[tot]=rdn();
        x[tot]=i; y[tot]=j;
        if(w[tot])continue; cnt++; bin[cnt]=bin[cnt-1]<<1;
        dp[tot][bin[cnt-1]]=0;
          }
      for(int s=1;s<bin[cnt];s++)
        {
          for(int i=1;i<=tot;i++)
        for(int d=(s-1)&s;d;d=(d-1)&s)
          if(dp[i][d]+dp[i][s^d]-w[i]<dp[i][s])//-w[i]!
            {
              dp[i][s]=dp[i][d]+dp[i][s^d]-w[i];
              to[i][s][0][0]=to[i][s][1][0]=i;
              to[i][s][0][1]=d; to[i][s][1][1]=s^d;
            }
          spfa(s);
        }
      int ans=INF,cr[2]={0,bin[cnt]-1};
      for(int i=1;i<=tot;i++)
        if(dp[i][bin[cnt]-1]<ans)ans=dp[i][bin[cnt]-1],cr[0]=i;
      solve(cr[0],cr[1]);
      printf("%d
    ",ans);
      for(int i=1;i<=n;i++,puts(""))
        for(int j=1;j<=m;j++)
          if(!w[bh[i][j]])putchar('x');
          else if(ch[i][j]=='o')putchar('o');
          else putchar('_');
      return 0;
    }
  • 相关阅读:
    学习进度三
    开课博客之个人介绍
    个人作业--数组
    学习进度二
    开学第一次测试
    实现点击不同的按钮加载不同的css
    Web存储
    HTML5(常用的表单控件)
    JS(获得当前时间并且用2015-01-01格式表示)
    JS(event事件)
  • 原文地址:https://www.cnblogs.com/Narh/p/10235313.html
Copyright © 2011-2022 走看看