题目链接:点击查看
题目大意:给出 n 个点( n 为偶数 ),题目需要求出两个完全没有交集的匹配 q 和 p ,一方面使得 n 个点两两互相匹配,另一方面使得匹配的权值和最小
题目分析:一道 dp 题,比赛时贪心WA了一下午,就比较自闭了
因为 n 是偶数,所以可以考虑将 n 个数分配到不同的长度为偶数的环中,对于排列 q 和排列 p,只需要在偶环中交换一下位置就好了
但这个偶环的长度必须要大于 2 ,因为如果长度为 2 的话,那么无法保证两个匹配 q 和 p 不存在交集
还有一个需要观察或者猜出的结论就是,任意长度大于等于 8 的偶环,都可以分解为长度为 4 和长度为 6 的偶环,且总边权更小
那么现在就对于长度为 4 和长度为 6 的偶环计算一下贪心可以获得的最小边权之和是多少吧,直接上图:
这样总结一下,对于长度为 x 的偶环( x = 4 或 x = 6 ),贪心可以得到的最小权值和为 2 * ( a[ i ] - a[ i - x ] ) ,注意 a 数组是排序后的数组
这样我们直接进行动态规划就好了
代码:
#include<iostream>
#include<cstdio>
#include<string>
#include<ctime>
#include<cmath>
#include<cstring>
#include<algorithm>
#include<stack>
#include<climits>
#include<queue>
#include<map>
#include<set>
#include<sstream>
#include<cassert>
#include<bitset>
using namespace std;
typedef long long LL;
typedef unsigned long long ull;
const int inf=0x3f3f3f3f;
const int N=2e5+100;
int a[N];
LL dp[N];
int main()
{
#ifndef ONLINE_JUDGE
// freopen("data.in.txt","r",stdin);
// freopen("data.out.txt","w",stdout);
#endif
// ios::sync_with_stdio(false);
int w;
cin>>w;
while(w--)
{
int n;
scanf("%d",&n);
for(int i=1;i<=n;i++)
scanf("%d",a+i);
sort(a+1,a+1+n);
dp[0]=0;
dp[2]=inf;
dp[4]=a[4]-a[1];
for(int i=6;i<=n;i+=2)
dp[i]=min(dp[i-4]+a[i]-a[i-3],dp[i-6]+a[i]-a[i-5]);
printf("%lld\n",2*dp[n]);
}
return 0;
}