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.
  • 相关阅读:
    HDOJ 4747 Mex
    HDU 1203 I NEED A OFFER!
    HDU 2616 Kill the monster
    HDU 3496 Watch The Movie
    Codeforces 347A A. Difference Row
    Codeforces 347B B. Fixed Points
    Codeforces 372B B. Hungry Sequence
    HDU 1476 Sudoku Killer
    HDU 1987 How many ways
    HDU 2564 词组缩写
  • 原文地址:https://www.cnblogs.com/myx12345/p/7986041.html
Copyright © 2011-2022 走看看