hdu 5691 Sitting in Line
Posted njczy2010
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了hdu 5691 Sitting in Line相关的知识,希望对你有一定的参考价值。
Sitting in Line
Time Limit: 10000/5000 MS (Java/Others) Memory Limit: 262144/262144 K (Java/Others)
Total Submission(s): 293 Accepted Submission(s): 143
Problem Description
度度熊是他同时代中最伟大的数学家,一切数字都要听命于他。现在,又到了度度熊和他的数字仆人们玩排排坐游戏的时候了。游戏的规则十分简单,参与游戏的N个整数将会做成一排,他们将通过不断交换自己的位置,最终达到所有相邻两数乘积的和最大的目的,参与游戏的数字有整数也有负数。度度熊为了在他的数字仆人面前展现他的权威,他规定某些数字只能在坐固定的位置上,没有被度度熊限制的数字则可以自由地交换位置。
Input
第一行一个整数T,表示T组数据。
每组测试数据将以如下格式从标准输入读入:
N
a1p1
a2p2
:
aNPN
第一行,整数 N(1≤N≤16),代表参与游戏的整数的个数。
从第二行到第 (N+1) 行,每行两个整数,ai(−10000≤ai≤10000)、pi(pi=−1 或 0≤pi<N),以空格分割。ai代表参与游戏的数字的值,pi代表度度熊为该数字指定的位置,如果pi=−1,代表该数字的位置不被限制。度度熊保证不会为两个数字指定相同的位置。
每组测试数据将以如下格式从标准输入读入:
N
a1p1
a2p2
:
aNPN
第一行,整数 N(1≤N≤16),代表参与游戏的整数的个数。
从第二行到第 (N+1) 行,每行两个整数,ai(−10000≤ai≤10000)、pi(pi=−1 或 0≤pi<N),以空格分割。ai代表参与游戏的数字的值,pi代表度度熊为该数字指定的位置,如果pi=−1,代表该数字的位置不被限制。度度熊保证不会为两个数字指定相同的位置。
Output
第一行输出:"Case #i:"。i代表第i组测试数据。
第二行输出数字重新排列后最大的所有相邻两数乘积的和,即max{a1⋅a2+a2⋅a3+......+aN−1⋅aN}。
第二行输出数字重新排列后最大的所有相邻两数乘积的和,即max{a1⋅a2+a2⋅a3+......+aN−1⋅aN}。
Sample Input
2
6
-1 0
2 1
-3 2
4 3
-5 4
6 5
5
40 -1
50 -1
30 -1
20 -1
10 -1
Sample Output
Case #1:
-70
Case #2:
4600
Source
Recommend
题意:
数组中有些元素位置被固定了,有些可以换位置,求
max{a1⋅a2+a2⋅a3+......+aN−1⋅aN}
题解:
真不容易,田神给我说了思路,还编了好久2333
状压dp,比赛时没时间思考了。。。
其实,观察所要求的max{a1⋅a2+a2⋅a3+......+aN−1⋅aN}
可以发现,你发完前 i - 1 位 元素后,准备放第 i 位 元素时,当前的 max 只 与 a[i-1] 有关了 (a[i - 1] * a[i]),所以可以用状压dp
定义 dp[o][i] 为放完第i位(以a[i] 为结尾),状态 o 时的max
遍历的顺序见代码
17232841 | 2016-05-21 22:22:30 | Accepted | 5691 | 1294MS | 11724K | 2946B | G++ | czy |
1 #include <iostream> 2 #include <cstdio> 3 #include <cstdlib> 4 #include <cstring> 5 #include <algorithm> 6 #include <vector> 7 8 using namespace std; 9 10 #define N 19 11 #define ll long long 12 13 ll ma; 14 ll a[N]; 15 int p[N]; 16 int have[N]; 17 int n; 18 ll dp[ (1 << 17) ][N]; 19 int tot; 20 ll inf; 21 vector<int> G[N]; 22 23 int cal(int x) 24 { 25 int ret = 0; 26 while(x){ 27 ret += (x & 1); 28 x /= 2; 29 } 30 return ret; 31 } 32 33 void ini() 34 { 35 int o; 36 for(o = 0;o < n;o++){ 37 G[o].clear(); 38 } 39 for(o = 0;o < tot;o++){ 40 G[ cal(o) ].push_back(o); 41 } 42 } 43 44 int main() 45 { 46 47 int T; 48 //freopen("in.txt","r",stdin); 49 //freopen("out.txt","w",stdout); 50 scanf("%d",&T); 51 for(int ccnt = 1;ccnt <= T;ccnt++){ 52 scanf("%d",&n); 53 inf = (1LL << 60); 54 ma = -inf; 55 tot = (1 << n); 56 ini(); 57 int i; 58 memset(have,-1,sizeof(have)); 59 for(i = 0;i < n;i++){ 60 scanf("%I64d%d",&a[i],&p[i]); 61 if(p[i] != -1){ 62 have[ p[i] ] = i; 63 } 64 } 65 int o,nt; 66 for(o = 0;o < tot;o++){ 67 for(i = 0;i < n;i++){ 68 dp[o][i] = -inf; 69 } 70 } 71 for(i = 0;i < n;i++){ 72 if(p[i] == 0 || p[i] == -1){ //放在第一个 73 dp[ (1 << i) ][i] = 0; 74 } 75 } 76 77 /* 78 for(i = 0;i < n;i++){ 79 for(int j = 0;j < G[i].size();j++){ 80 printf(" i =%d j = %d g= %d\n",i,j,G[i][j]); 81 } 82 }*/ 83 for(i = 1;i < n;i++){ //放第i位 84 int sz = G[i].size(); 85 for(int j = 0;j < sz;j++){ //遍历含有i个1的所有数 86 o = G[i][j]; 87 for(int k = 0;k < n;k++) //把第k个数放在第i位 88 { 89 90 if( o & (1 << k) ) continue; //k已经放了 91 if( p[k] != -1 && p[k] != i ) continue; //k被固定了 92 if( have[i] != -1 && have[i] != k ) continue; //位置i被固定了 93 nt = o | (1 << k); 94 //printf(" i = %d o = %d k = %d nt = %d\n",i,o,k,nt); 95 for(int pr = 0;pr < n;pr++){ 96 if( (o & (1 << pr ) ) == 0) continue; //pr不在o里 97 if( dp[o][pr] == -inf ) continue; 98 //printf(" i = %d o = %d k = %d nt = %d pr = %d\n",i,o,k,nt,pr); 99 dp[nt][k] = max(dp[nt][k],dp[o][pr] + a[pr] * a[k]); 100 } 101 } 102 } 103 } 104 /* 105 for(o = 0;o < tot;o++){ 106 for(i = 0;i < n;i++){ 107 printf(" o = %d i = %d dp = %I64d\n",o,i,dp[o][i]); 108 } 109 }*/ 110 for(i = 0;i < n;i++){ 111 ma = max(ma,dp[tot - 1][i]); 112 } 113 printf("Case #%d:\n",ccnt); 114 printf("%I64d\n",ma); 115 } 116 117 return 0; 118 }
以上是关于hdu 5691 Sitting in Line的主要内容,如果未能解决你的问题,请参考以下文章
HDU 5691 ——Sitting in Line——————状压动规
hdu 5691 Sitting in Line(状压dp)