JZOJ 3166. 【GDOI2013模拟3】火星菌(DP)

JZOJ 3166.【GDOI2013模拟3】火星菌

题目

Description

科学家发现火星上有一种奇怪的细菌,每天产生的新细菌数量是 2 2 2的幂,因为每天新产生的细菌会在下一天产生两个新细菌,第一天只有一个细菌。因此,第一天有 1 1 1个细菌,第二天有 2 2 2个,第三天有 4 4 4个,。。。,第 k + 1 k+1 k+1天有 2 k 2^k 2k 个细菌。用 1 1 1 2 k 2^k 2k对这 2 k 2^k 2k个细菌进行编号,同时满足:

k k k天的细菌的子孙分别是 ( 1 , 2 ) , ( 3 , 4 ) , ( 5 , 6 ) , 。 。 。 , ( 2 k − 1 , 2 k ) (1,2),(3,4),(5,6),。。。,(2^k-1,2^k) (1,2)(3,4)(5,6),(2k1,2k)

k − 1 k-1 k1天的细菌的子孙分别是 ( 1 , 2 , 3 , 4 ) , ( 5 , 6 , 7 , 8 ) , 。 。 。 , ( 2 k − 3 , 2 k − 2 , 2 k − 1 , 2 k ) (1,2,3,4),(5,6,7,8),。。。,(2^k-3,2^k-2,2^k-1,2^k) (1,2,3,4)(5,6,7,8)(2k3,2k2,2k1,2k)

k − 2 k-2 k2天的细菌的子孙分别是 ( 1 , 2 , 3 , 4 , 5 , 6 , 7 , 8 ) , 。 。 。 , ( 2 k − 7 , 2 k − 6 , 2 k − 5 , 2 k − 4 , 2 k − 3 , 2 k − 2 , 2 k − 1 , 2 k ) (1,2,3,4,5,6,7,8),。。。,(2^k-7,2^k-6,2^k-5,2^k-4,2^k-3,2^k-2,2^k-1,2^k) (1,2,3,4,5,6,7,8)(2k7,2k6,2k5,2k4,2k3,2k2,2k1,2k)

。。。

2 2 2天的细菌的子孙分别是 ( 1 , 2 , 3 , . . . , 2 k − 1 ) , ( 2 k − 1 + 1 , 2 k − 1 + 2 , . . . , 2 k ) (1,2,3,..., 2^{k-1}),(2^{k-1}+1,2^{k-1}+2,...,2^k) (1,2,3,...,2k1)(2k1+1,2k1+2,...,2k)

其中括号括起来的集合里面的元素是一个细菌的子孙,以上对第 k + 1 k+1 k+1天的 2 k 2^k 2k个细菌的编号方式满足:前面任何一天的任何一个细菌的子孙编号都是连续的数字。

但编号方法不是唯一的,可能有很多种方法,现在给定任意两个编号 i i i j j j之间的权值 w [ i ] [ j ] w[i][j] w[i][j],要求找到 1 1 1 2 k 2^k 2k的一个排列 A 1 , A 2 , . . . . , A 2 k − 1 , A 2 k A_1,A_2,....,A_{2^k-1},A_{2^k} A1,A2,....,A2k1,A2k满足前面任何一天的细菌的子孙都对应着一段连续的数字,同时要求排列的权值 w [ A 1 ] [ A 2 ] + w [ A 2 ] [ A 3 ] + . . . . + w [ A 2 k − 1 ] [ A 2 k ] w[A_1][A_2]+w[A_2][A_3]+....+w[A_{2^k-1}][A_{2^k}] w[A1][A2]+w[A2][A3]+....+w[A2k1][A2k]最小。

Input

第一行输入一个整数 k ( 1 ≤ k ≤ 9 ) k(1≤k≤9) k(1k9)

接下来 2 k 2^k 2k行,每行输入 2 k 2^k 2k个数,范围在 0 0 0 1 0 6 10^6 106之间,表示 w [ i ] [ j ] w[i][j] w[i][j]

当然输入保证 w [ i ] [ j ] = w [ j ] [ i ] w[i][j]=w[j][i] w[i][j]=w[j][i] w [ i ] [ i ] = 0 w[i][i]=0 w[i][i]=0.

Output

输出一个数表示满足条件的 1 1 1 2 k 2^k 2k的排列的最小权值。

Sample Input

输入1:
2
0 7 2 1
7 0 4 3
2 4 0 5
1 3 5 0

输入2:
3
0 2 6 3 4 7 1 3
2 0 7 10 9 1 3 6
6 7 0 3 5 6 5 5
3 10 3 0 9 8 9 7
4 9 5 9 0 9 8 4
7 1 6 8 9 0 8 7
1 3 5 9 8 8 0 10
3 6 5 7 4 7 10 0

Sample Output

输出1:
13

输出2:
32

Data Constraint

100%的数据满足 1 ≤ k ≤ 9 1≤k≤9 1k9.

Hint

样例1 中满足条件的排列有 ( 1 , 2 , 3 , 4 ) 、 ( 1 , 2 , 4 , 3 ) 、 ( 2 , 1 , 3 , 4 ) 、 ( 2 , 1 , 4 , 3 ) 、 ( 3 , 4 , 1 , 2 ) 、 ( 3 , 4 , 2 , 1 ) 、 ( 4 , 3 , 1 , 2 ) 、 ( 4 , 3 , 2 , 1 ) (1,2,3,4)、(1,2,4,3)、(2,1,3,4)、(2,1,4,3)、(3,4,1,2)、(3,4,2,1)、(4,3,1,2)、(4,3,2,1) (1,2,3,4)(1,2,4,3)(2,1,3,4)(2,1,4,3)(3,4,1,2)(3,4,2,1)(4,3,1,2)(4,3,2,1)对应的权值分别为 16 、 15 、 14 、 13 、 13 、 15 、 14 、 16 16、15、14、13、13、15、14、16 1615141313151416,权值最小的排列为 ( 2 , 1 , 4 , 3 ) (2,1,4,3) (2,1,4,3) ( 3 , 4 , 1 , 2 ) (3,4,1,2) (3,4,1,2),都是 13 13 13.

题解

  • 这道题目的描述太太太太太复杂了!!
  • 简化题面:
  • 建一棵满二叉数(类似一棵线段树),
  • 0 0 0层—— [ 1 , 2 k ] [1,2^k] [1,2k]
  • 1 1 1层—— [ 1 , 2 k − 1 ] , [ 2 k − 1 + 1 , 2 k ] [1,2^{k-1}],[2^{k-1}+1,2^k] [1,2k1][2k1+1,2k]
  • ……
  • k k k层—— 1 , 2 , 3 … … 2 k 1,2,3……2^k 1,2,32k
  • 每个节点有两个子树(类似线段树),允许把任何一个节点的左右子树进行交换,最后第 k k k层不一定是 1 − 2 k 1-2^k 12k升序排列,可能是乱序的。
  • 问经过这样的随意交换后,最小的第 k k k层的序列每相邻两个数的 w w w值之和。
  • 考虑用DP解决:
  • f [ i ] [ j ] f[i][j] f[i][j]为最后一层第 i i i个数为 j j j的最小值,转移不难想到:
    f [ i ] [ j ] = m i n ( f [ i ] [ j ] , f [ i − 1 ] [ h ] ) f[i][j]=min(f[i][j],f[i-1][h]) f[i][j]=min(f[i][j],f[i1][h])
  • (其中 h h h是枚举的)
  • 这成为一个不易解决的问题, h h h的范围是多少?
  • 把整个序列想象成很多块,
  • 1 1 1个大小为 2 k 2^k 2k的块, 2 2 2个大小为 2 k − 1 2^{k-1} 2k1的块…… 2 k 2^k 2k个大小为 1 1 1的块,按从左到右的顺序分开。
  • 找到一个 p p p,使 i i i i − 1 i-1 i1不在同一个大小为 p p p的块中,最大化 p p p.( p p p一定是 2 2 2的幂数)
  • 接着看 j j j所在的大小为 p p p的块是第 x x x个,找到 x x x.
  • 那么若 x x x为奇数, h h h的范围就是第 x + 1 x+1 x+1个大小为 p p p的块的范围;
  • x x x为偶数, h h h的范围就是第 x − 1 x-1 x1个大小为 p p p的块的范围。
  • 举个例子:
  • 当前 i = 5 , j = 35 i=5,j=35 i=5j=35
  • 发现 i i i i − 1 i-1 i1在同一个大小为 8 8 8的块中 [ 1 , 8 ] [1,8] [1,8],不在同一个大小为 4 4 4的块中 [ 1 , 4 ] [1,4] [1,4] [ 5 , 8 ] [5,8] [5,8],则 p p p 4 4 4.
  • j j j在第 9 9 9个大小为 4 4 4的块中 [ 33 , 36 ] [33,36] [33,36],那么 h h h的范围就是 [ 37 , 40 ] [37,40] [37,40].
  • 先把题目大意理解清楚,题解多看几遍,自己画一画图,很快就会明白的!

代码

#include<cstdio>
#include<cstring>
using namespace std;
int e[10],w[520][520],f[520][520];
int main()
{
	int n,i,j,k;
	e[0]=1;
	for(i=1;i<=9;i++) e[i]=e[i-1]*2;
	scanf("%d",&n);
	for(i=0;i<e[n];i++)
		for(j=0;j<e[n];j++) scanf("%d",&w[i][j]);

	for(i=0;i<e[n];i++) f[0][i]=0;
	
	for(i=1;i<e[n];i++)
		for(j=0;j<e[n];j++)
		{
			f[i][j]=2147483647;
			int l,r;
			
			for(k=n;k>=0;k--)
			{
				if(i/e[k]!=(i-1)/e[k])
				{
					int x=j/e[k];
					x^=1;
					l=x*e[k];
					r=l+e[k]-1;
					break;
				}
			}
			
			for(k=l;k<=r;k++) if(f[i-1][k]+w[j][k]<f[i][j]) f[i][j]=f[i-1][k]+w[j][k];
		}
		
	int ans=2147483647;
	for(i=0;i<e[n];i++) if(f[e[n]-1][i]<ans) ans=f[e[n]-1][i];
	
	printf("%d",ans);
	return 0;
}
哈哈哈哈哈哈哈哈哈哈
原文地址:https://www.cnblogs.com/LZA119/p/13910088.html