题意
给你一个 2 × n 2\times n 2×n的棋盘,经过格子 ( i , j ) (i,j) (i,j)就会获得权值 a i , j a_{i,j} ai,j
重新排列整个棋盘,使得从左上角走到右下角的路径权值和的最大值最小(只能向下或者向右走)
2 ≤ n ≤ 25 , 0 ≤ a i , j ≤ 5 × 1 0 4 ( 1 ≤ i ≤ 2 , 1 ≤ j ≤ n ) 2\le n\le25,0\le a_{i,j}\le5\times10^4(1\le i\le2,1\le j\le n) 2≤n≤25,0≤ai,j≤5×104(1≤i≤2,1≤j≤n)
题解
考虑交换同一行两个数的位置对最大值的影响
变成
那么有的路径权值和不会改变,有的路径取值和会减小,这样路径最大值就有可能减小
所以第一行升序排序更优,同理可得第二行降序排列更优
考虑对于一种已经排好序的棋盘答案多少
考虑两个相邻路径的权值和的差异
x 1 x_1 x1 | … | x i x_i xi | x i + 1 x_{i+1} xi+1 | … | x n x_n xn |
---|---|---|---|---|---|
y 1 y_1 y1 | … | y i y_i yi | y i + 1 y_{i+1} yi+1 | … | y n y_n yn |
对于路径 x 1 → . . . → x i → y i → . . . → y n x_1\rightarrow...\rightarrow x_i\rightarrow y_i\rightarrow...\rightarrow y_n x1→...→xi→yi→...→yn和路径 x 1 → . . . → x i → x i + 1 → y i + 1 → . . . → y n x_1\rightarrow...\rightarrow x_i\rightarrow x_{i+1}\rightarrow y_{i+1}\rightarrow...\rightarrow y_n x1→...→xi→xi+1→yi+1→...→yn
他们的权值差的绝对值就是 Δ i = ∣ x i + 1 − y i ∣ \Delta_i=|x_{i+1}-y_i| Δi=∣xi+1−yi∣,由于 x x x递增, y y y递减
所以 Δ i \Delta_i Δi的函数图像就长这样
所以最大值就一定会在两边取到,即最大值为 max ( ∑ i = 1 n x i + y n , x 1 + ∑ i = 1 n y i ) = x 1 + y n + max ( ∑ i = 2 n x i , ∑ i = 1 n − 1 y i ) \max(\sum_{i=1}^nx_i+y_n,x_1+\sum_{i=1}^ny_i)=x_1+y_n+\max(\sum_{i=2}^nx_i,\sum_{i=1}^{n-1}y_i) max(∑i=1nxi+yn,x1+∑i=1nyi)=x1+yn+max(∑i=2nxi,∑i=1n−1yi)
把最小的两个数拿走,问题就转化成了:给你一个有 m m m个数的序列 a a a,将其分成两个等大的集合 A , B A,B A,B,最小化 max ( ∑ A , ∑ B ) \max(\sum A,\sum B) max(∑A,∑B)
这个问题实质上就是一个背包问题
先把 a a a从小到大排序,设 S u m = ∑ a Sum=\sum a Sum=∑a
设 f [ i ] [ j ] [ k ] f[i][j][k] f[i][j][k]表示前 i i i个数中放 j j j个数在集合 A A A中,且 ∑ A = k \sum A=k ∑A=k的情况是否存在
那么 f [ i ] [ j ] [ k ] = f [ i − 1 ] [ j ] [ k ] ∣ f [ i − 1 ] [ j − 1 ] [ k − a i ] f[i][j][k]=f[i-1][j][k]|f[i-1][j-1][k-a_i] f[i][j][k]=f[i−1][j][k]∣f[i−1][j−1][k−ai]
那么 A n s = min { max ( k , S u m − k ) } Ans=\min\{\max(k,Sum-k)\} Ans=min{max(k,Sum−k)},可见 A n s Ans Ans越靠近 S u m 2 \frac{Sum}2 2Sum越小
然后根据 A n s Ans Ans寻找转移路径输出答案即可
一个小优化是 f f f的转移可以用 C + + C++ C++的 b i t s e t bitset bitset实现
时间复杂度 O ( 1 64 n 2 ∑ a ) O(\frac1{64}n^2\sum a) O(641n2∑a)
#include<bits/stdc++.h>
#define fp(i,a,b) for(register int i=a,I=b+1;i<I;++i)
#define fd(i,a,b) for(register int i=a,I=b-1;i>I;--i)
#define file(s) freopen(s".in","r",stdin),freopen(s".out","w",stdout)
using namespace std;
const int N=55,M=50*5e4+5;
typedef long long ll;
int n,m;
bitset<M>f[52][26];
int main(){
#ifndef ONLINE_JUDGE
file("s");
#endif
scanf("%d",&n);m=(--n)<<1;
vector<int>a(m+3),Ans[2];
fp(i,1,m+2)scanf("%d",&a[i]);
sort(a.begin()+1,a.end());
Ans[0].push_back(a[1]);a.erase(a.begin()+1);
Ans[1].push_back(a[1]);a.erase(a.begin()+1);
f[0][0][0]=1;
fp(i,1,m){
f[i][0][0]=1;
fp(j,1,min(n,i))
f[i][j]=f[i-1][j]|(f[i-1][j-1]<<a[i]);
}
int Cur=accumulate(a.begin()+1,a.end(),0)>>1,Cnt=n;
while(!f[m][n][Cur])--Cur;
fd(i,m,1)
if(a[i]>Cur||!f[i-1][Cnt-1][Cur-a[i]])
Ans[0].push_back(a[i]);
else Ans[1].push_back(a[i]),Cur-=a[i],--Cnt;
sort(Ans[0].begin(),Ans[0].end());
sort(Ans[1].begin(),Ans[1].end(),greater<int>());
fp(i,0,1)fp(j,0,n)printf("%d%c",Ans[i][j]," \n"[j==n]);
return 0;
}