zoukankan      html  css  js  c++  java
  • 【NOIP2017】宝藏(状压DP)

    题意:

    思路:n<=12,考虑状压DP

    生成树中深度相同的点可以一次性转移完毕

    设dp[sta,i]为已转移完sta状态的点,当前深度为i的最小花费

    dp[sta or v,i+1]=min(dp[sta,i]+f[sta,v]*(i+1)),其中v是sta关于全集(1<<n)-1的补集v1的一个子集,这一步需要枚举子集

    考场上写的O(3^n*n^2),没有预处理f[sta,v]而是每次都算了一遍,有进一步优化的空间

     1 const max=500001;
     2 var dp,dis:array[0..5000,0..20]of int64;
     3     f:array[1..20,1..20]of int64;
     4     n,m,i,j,x,y,z,k,maxs,v,v1:longint;
     5     s,ans:int64;
     6 
     7 function min(x,y:int64):int64;
     8 begin
     9  if x<y then exit(x);
    10  exit(y);
    11 end;
    12 
    13 begin
    14  assign(input,'treasure.in'); reset(input);
    15  assign(output,'treasure.out'); rewrite(output);
    16  readln(n,m);
    17  for i:=1 to n do
    18   for j:=1 to n do f[i,j]:=1<<60;
    19  for i:=1 to n do f[i,i]:=0;
    20  for i:=1 to m do
    21  begin
    22   readln(x,y,z);
    23   f[x,y]:=min(f[x,y],z);
    24   f[y,x]:=min(f[y,x],z);
    25  end;
    26  maxs:=(1<<n)-1;
    27  for i:=1 to maxs do
    28   for j:=1 to n do
    29    if i and (1<<(j-1))=0 then
    30    begin
    31     dis[i,j]:=1<<60;
    32     for k:=1 to n do
    33      if (j<>k)and(i and (1<<(k-1))>0) then dis[i,j]:=min(dis[i,j],f[j,k]);
    34    end;
    35 
    36  m:=maxs;
    37  for i:=1 to maxs do
    38   for j:=0 to n+1 do dp[i,j]:=1<<60;
    39  for i:=1 to n do dp[1<<(i-1),0]:=0;
    40  for i:=0 to n do
    41   for j:=1 to maxs do
    42   begin
    43    v:=j xor m; v1:=v;
    44    while v>0 do
    45    begin
    46     s:=0;
    47     for k:=1 to n do
    48      if v and (1<<(k-1))>0 then
    49      begin
    50       s:=s+dis[j,k];
    51       if s>=(1<<60) then break;
    52      end;
    53     if s<(1<<60) then
    54      dp[j or v,i+1]:=min(dp[j or v,i+1],dp[j,i]+s*(i+1));
    55     v:=v1 and (v-1);
    56    end;
    57   end;
    58  ans:=1<<60;
    59  for i:=1 to n+1 do ans:=min(ans,dp[maxs,i]);
    60  if n=1 then ans:=0;
    61  writeln(ans);
    62 
    63 
    64  close(input);
    65  close(output);
    66 end.

     O(3^n*n),预处理两个值

    d[sta,i]      已取sta状态中的点到i点的最小值 预处理O(2^n*n^2)

    f[x,y]      x状态中的点和y状态中的所有点连接最小长度之和=f[x,y-lowbit(y)]+d[x,z],z表示y中最后一个1的位置 预处理O(4^n) 需要保证x与y没有交集

     1 const max=500001;
     2 var dp,d:array[0..5000,0..20]of int64;
     3     dis:array[0..5000,0..5000]of int64;
     4     f:array[1..20,1..20]of int64;
     5     num:array[1..5000]of longint;
     6     n,m,i,j,x,y,z,k,maxs,v,v1:longint;
     7     s,ans:int64;
     8 
     9 function min(x,y:int64):int64;
    10 begin
    11  if x<y then exit(x);
    12  exit(y);
    13 end;
    14 
    15 function lowbit(x:longint):longint;
    16 begin
    17  exit(x and (-x));
    18 end;
    19 
    20 begin
    21  assign(input,'treasure.in'); reset(input);
    22  assign(output,'treasure.out'); rewrite(output);
    23  readln(n,m);
    24  for i:=1 to n do
    25   for j:=1 to n do f[i,j]:=1<<60;
    26  for i:=1 to n do f[i,i]:=0;
    27  for i:=1 to m do
    28  begin
    29   readln(x,y,z);
    30   f[x,y]:=min(f[x,y],z);
    31   f[y,x]:=min(f[y,x],z);
    32  end;
    33 
    34  maxs:=(1<<n)-1;
    35  for i:=1 to maxs do
    36   for j:=1 to n do
    37    if i and (1<<(j-1))=0 then
    38    begin
    39     d[i,j]:=1<<60;
    40     for k:=1 to n do
    41      if (j<>k)and(i and (1<<(k-1))>0) then d[i,j]:=min(d[i,j],f[j,k]);
    42    end;
    43 
    44  m:=maxs;
    45  for i:=1 to 12 do num[1<<(i-1)]:=i;
    46  for i:=1 to maxs do
    47   for j:=1 to maxs do dis[i,j]:=1<<60;
    48  for i:=0 to maxs do dis[0,i]:=0;
    49  for i:=0 to maxs do dis[i,0]:=0;
    50 
    51  for i:=1 to maxs do
    52   for j:=1 to maxs do
    53    if i and j=0 then
    54    begin
    55     x:=num[lowbit(j)];
    56     dis[i,j]:=dis[i,j-lowbit(j)]+d[i,x];
    57     if dis[i,j]>(1<<60) then dis[i,j]:=1<<60;
    58    end;
    59 
    60  for i:=1 to maxs do
    61   for j:=0 to n+1 do dp[i,j]:=1<<60;
    62  for i:=1 to n do dp[1<<(i-1),0]:=0;
    63  for i:=0 to n do
    64   for j:=1 to maxs do
    65   begin
    66    v:=j xor m; v1:=v;
    67    while v>0 do
    68    begin
    69     if dis[j,v]<1<<60 then
    70      dp[j or v,i+1]:=min(dp[j or v,i+1],dp[j,i]+dis[j,v]*(i+1));
    71     v:=v1 and (v-1);
    72    end;
    73   end;
    74 
    75  ans:=1<<60;
    76  for i:=1 to n+1 do ans:=min(ans,dp[maxs,i]);
    77  if n=1 then ans:=0;
    78  writeln(ans);
    79 
    80 
    81  close(input);
    82  close(output);
    83 end.
  • 相关阅读:
    [转]html5 Canvas画图教程(6)—canvas里画曲线之arcTo方法
    [转]html5 Canvas画图教程(5)—canvas里画曲线之arc方法
    [转]html5 Canvas画图4:填充和渐变
    [转]html5 Canvas画图教程(3)—canvas出现1像素线条模糊不清的原因
    [转]html5 Canvas画图教程(2)—画直线与设置线条的样式如颜色/端点/交汇点
    【Java进阶】Maven 简介
    【Java入地】Spring 的 作用域 & MVC & SSM
    【Linux】Kali 物理机安装笔记、简单过程及注意事项
    【电脑维修】 显卡错误(错误代码:43)
    【Linux】 编程环境搭建 JDK、Node.js、Npm、Yarn、Redis、Maven的安装与搭建
  • 原文地址:https://www.cnblogs.com/myx12345/p/7986041.html
Copyright © 2011-2022 走看看