2019牛客国庆集训派对day3 排列(状压dp)
Posted issue是fw
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了2019牛客国庆集训派对day3 排列(状压dp)相关的知识,希望对你有一定的参考价值。
状压每个位置是否被填充数字
考虑从小到大把数字填充进去,这样就可以去掉绝对值符号
#include<bits/stdc++.h>
using namespace std;
#define int long long
const int inf = 1e18;
const int maxn = 1<<21;
int n,m,a[maxn],b[maxn],z[maxn],y[maxn];
int bit[maxn],sumz[maxn],sumy[maxn],p[22],f[maxn];
signed main()
{
bit[0] = 0;
for(int i=1;i<maxn;i++) bit[i] = bit[i>>1]+(i&1);
while( cin >> n >> m )
{
for(int i=1;i<=n;i++) cin >> p[i];
for(int i=1;i<=m;i++)
{
cin >> a[i] >> b[i];
z[a[i]] |= (1<<(b[i]-1));
y[b[i]] |= (1<<(a[i]-1));
sumz[a[i]]++, sumy[b[i]]++;
}
sort( p+1,p+1+n );
int mx = 1<<n;
for(int i=1;i<mx;i++) f[i] = inf;
for(int i=0;i<mx;i++)//枚举状态
for(int j=1;j<=n;j++)//枚举哪个位置被放了数字
{
if( i&(1<<(j-1)) )
{
//当前放置的数字是剩余数字中最小的
int t = i-(1<<(j-1)), v = p[bit[i]];
int zuo = i&z[j];//作为左边的时候,有多少比自己小的数在右边
int you = i&y[j];//作为右边的时候,有多少个数在左边
int temp = v*( bit[zuo]+bit[you] )-v*( sumz[j]+sumy[j]-bit[zuo]-bit[you] );
f[i] = min( f[i],f[t]+temp );
}
}
cout << f[mx-1] << endl;
for(int i=0;i<=n;i++) z[i] = y[i] = sumz[i] = sumy[i] = 0;
}
}
以上是关于2019牛客国庆集训派对day3 排列(状压dp)的主要内容,如果未能解决你的问题,请参考以下文章
2019牛客国庆集训派对day3 J.买一送一(dfs+组合数学)
2019牛客国庆集训派对day1 D.Modulo Nine(巧妙的dp)
2019牛客国庆集训派对day1 F.4 Buttons(思维)