【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.
null