zoukankan      html  css  js  c++  java
  • [noip2017]宝藏

    https://www.zybuluo.com/ysner/note/1286437

    题面

    戳我

    解析

    这确实是一道搜索可以过的题。。。
    一般的暴力,就是枚举出发点,记录下当前已到过哪些点,以及每个点的深度((K)值),然后对每个状态枚举走的下一条路的起点和终点。
    当然,最优性剪枝谁都会。

    这样复杂度(O(3^nn^3))。可以获得(70pts)

    然而我们可以再加剪枝。
    对于出发点相同的同一状态,如果当前到达当前状态的费用比以前的大,就可以停止搜索。
    这样就可以(AC)。。。

    显然这个剪枝是有问题的,因为后面的结果还受当前状态中每个点的深度的影响。也可能当前不优,最后能最优呢。

    给一组数据(Hack)一下。(来自洛谷讨论版
    正确答案(1043)。我的代码去掉剪枝是(1043),加上剪枝(1046)
    我原来的(AC)代码

    il void upd(re int &x,re int y){x=x<y?x:y;}
    il void dfs(re int tag,re int sum)
    {
      if(sum>=ans) return;
      if(tag==(1<<n)-1) {upd(ans,sum);return;}
      fp(s,1,n)
        if(d[s])
       fp(t,1,n)
         if(!d[t]&&mp[s][t]!=inf)
         {
           re int nxt=tag|(1<<t-1),res=sum+d[s]*mp[s][t];
         if(f[nxt]>res)//剪枝
           {
         d[t]=d[s]+1;
         f[nxt]=res;
         dfs(nxt,res);
         d[t]=0;
           }
         }
    }
    int main()
    {
      n=gi();m=gi();
      fp(i,0,19) fp(j,0,19) mp[i][j]=inf;
      fp(i,1,m)
        {
          re int u=gi(),v=gi(),w=gi();
          mp[u][v]=mp[v][u]=min(mp[u][v],w);
        }
      fp(i,1,n)
        {
          memset(d,0,sizeof(d));memset(f,63,sizeof(f));
          d[i]=1;f[1<<i-1]=0;
          dfs(1<<i-1,0);
        }
      printf("%d
    ",ans);
      return 0;
    }
    

    下面来谈一谈有理有据的算法。
    用二进制表示结点集合,设(f[i][j])表示点(i)在当时可走点的集合为(j)的情况下,下一步走的距离最小是多少。
    此时点深度也是确定的,所以也能保证答案最小。

    再设(dp[i][j])表示当前加入深度为(i)的点,此时已加入点集合为(j)的最小代价。
    然后按照深度依次更新(dp)值,就没有后效性的问题了。
    具体来说,是先枚举深度,再枚举加完点后的集合,再枚举其子集(即加点前的集合)。最后在加点前的集合中枚举出发点,以统计(f)的和。

    复杂度(O(3^nn^2))
    所以这题应该放(T3)的。。。

    #include<iostream>
    #include<cstdio>
    #include<cstdlib>
    #include<cmath>
    #include<cstring>
    #include<algorithm>
    #include<queue>
    #define ll long long
    #define re register
    #define il inline
    #define db double
    #define fp(i,a,b) for(re int i=a;i<=b;++i)
    #define fq(i,a,b) for(re int i=a;i>=b;--i)
    using namespace std;
    const int inf=5e6;
    int n,m,f[13][1<<12],dis[13][13],g[13][1<<12],all;
    il ll gi()
    {
      re ll x=0,t=1;
      re char ch=getchar();
      while(ch!='-'&&(ch<'0'||ch>'9')) ch=getchar();
      if(ch=='-') t=-1,ch=getchar();
      while(ch>='0'&&ch<='9') x=x*10+ch-48,ch=getchar();
      return x*t;
    }
    il int max(re int x,re int y){return x>y?x:y;}
    int main()
    {
      n=gi();m=gi();all=(1<<n)-1;
      fp(i,1,12) fp(j,1,12) dis[i][j]=inf;
      fp(i,1,12) fp(j,0,all) f[i][j]=g[i][j]=inf;
      fp(i,1,m)
        {
          re int u=gi(),v=gi(),w=gi();
          dis[u][v]=dis[v][u]=min(dis[u][v],w);
        }
      fp(i,1,n) dis[i][i]=0;
      fp(S,0,all)
        fp(i,1,n)
        if((1<<i-1)&S)
          fp(j,1,n)
    	if(!((1<<j-1)&S))
    	  g[j][S]=min(g[j][S],dis[i][j]);
      fp(i,1,n) f[1][1<<i-1]=0;
      fp(i,2,n)
        fp(S,0,all)
        for(re int P=S;P;P=(P-1)&S)
          {
    	re int tot=0;
    	fp(j,1,n) if((1<<j-1)&(P^S)) tot+=g[j][P];
    	f[i][S]=min(f[i][S],f[i-1][P]+(i-1)*tot);
          }
      printf("%d
    ",f[n][all]);
      return 0;
    }
    
    
  • 相关阅读:
    js变量如何赋值给css使用?
    前端预览与下载PDF小结
    子组件如何改父组件传过来的值
    TensorRT转换时的静态模式与动态模式
    Linux:搭建GlusterFS文件系统
    OpenFeign传输文件MultipartFile
    Docker:commit、export、import、save、load命令的使用
    Git:代码版本回退
    docker安装Drools Workbench
    ArchLinux:Typora设置gitee图床
  • 原文地址:https://www.cnblogs.com/yanshannan/p/9671155.html
Copyright © 2011-2022 走看看