LINK-> 牛客
链接:https://ac.nowcoder.com/acm/contest/1108/G
来源:牛客网
排列
时间限制:C/C++ 1秒,其他语言2秒
空间限制:C/C++ 32768K,其他语言65536K
Special Judge, 64bit IO Format: %lld
题目描述
Bobo 有一个长度为 n 的数列 p1,p2,…,pnp_1, p_2, \dots, p_np1,p2,…,pn 和 m 个二元组 (a1,b1),(a2,b2),…,(am,bm)(a_1, b_1), (a_2, b_2), \dots, (a_m, b_m)(a1,b1),(a2,b2),…,(am,bm).
他想重新排列数列 p,使得 ∑i=1m∣pai−pbi∣\sum_{i = 1}^m |p_{a_i} - p_{b_i}|∑i=1m∣pai−pbi∣ 最小。求最小值。
输入描述:
输入文件包含多组数据,请处理到文件结束。
每组数据的第一行包含 2 个整数 n 和 m。
第二行包含 n 个整数 p1,p2,…,pnp_1, p_2, \dots, p_np1,p2,…,pn.
最后 m 行的第 i 行包含 2 个整数 aia_iai 和 bib_ibi.
输出描述:
对于每组数据输出 1 个整数表示所求的最小值。
感想吧 QAQ 最后五十分钟一直在怼的一道题,不知道为什么这题对我莫名吸引力,难得的是对题目的考察知识的感觉是对的,最后过了样例瞎交结果MLE ,开心的是个人感觉和AC代码还是长得很像的(
强行很像)
带注释的代码 (有错求指出,有更好的想法求分享诶~~)
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
ll dp[1<<20];
int p[21],mp[21],c[21];
const ll inf=1e18;
int main()
{
int n,m;while(~scanf("%d%d",&n,&m))
{
for(int i=0;i<n;i++) scanf("%d",&p[i]);
sort(p,p+n);int a,b;
for(int i=0;i<=n;i++) mp[i]=0,c[i]=0;
for(int i=0;i<m;i++)
{
scanf("%d%d",&a,&b );a--;b--;
mp[a ]++;mp[b ]++;
c[a]|=1<<b;//储存和a匹配的数
c[b]|=1<<a;
}
dp[0]=0ll;
for(int i=1;i<(1<<n);i++)//i中等于1 表示这些位置有值了
{
dp[i]=inf;
int now=__builtin_popcount(i)-1;//现在该放p[now]
for(int j=0;j<n;j++)
{
if((i>>j)&1)//p[now]放在j这个位置
{
dp[i]=min(dp[i],dp[(1<<j)^i]+1ll*p[now]*((__builtin_popcount(i&c[j]))*2-mp[j]));
}
// 已经和j匹配到的个数-还没和j匹配的个数
// (__builtin_popcount(i&c[j]))表示已经匹配完成的 , mp[j]表示全部含有j的序列数
// (__builtin_popcount(i&c[j]))*2-mp[j])就表示已经和j匹配到的-还没和j匹配的
//这样处理的原因
//由于处理的是|pa-pb|要保证结果是>=0
//之前的sort处理保证p递增所以
//这时候的pa值肯定比之前的pb值大,肯定比之后处理的pb值小
//所以这里它对于已经存在的匹配作为被减数 之后还没存在的匹配作为减数 so这里p[now] 出现的次数就是被减数-减数的次数
//以上就是我的一点理解吧
}
}
printf("%lld\n",dp[(1<<n)-1]);
}
}
- 没有注释的简洁版本
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
ll dp[1<<20];int c[21],mp[21],p[21];
const ll inf=1e18;
int main()
{
int n,m,a,b;while(~scanf("%d%d",&n,&m))
{
for(int i=0;i<n;i++) scanf("%d",&p[i]);sort(p,p+n);
for(int i=0;i<n;i++) c[i]=0,mp[i]=0;
for(int i=0;i<m;i++)
{
scanf("%d%d",&a,&b);
a--,b--;mp[a]++,mp[b]++;
c[a]|=1<<b,c[b]|=1<<a;
}
dp[0]=0ll;
for(int i=1;i<(1<<n);i++)
{
dp[i]=inf;
int now=__builtin_popcount(i)-1;
for(int j=0;j<n;j++)
{
if((i>>j)&1)
{
dp[i]=min(dp[i],dp[i^(1<<j)]+1ll*p[now]*(__builtin_popcount(i&c[j])*2-mp[j]));
}
}
}
printf("%lld\n",dp[(1<<n)-1]);
}
}