T180745 菌落合并
n很小,肯定状压之类的题目
显然普通的01不能够确定菌落的状态
利用变进制数即可:\(00112\)可以表示\(12\ 34\ 5\)分别为一个菌落,这样刚好存的下。
转移也很简单,但是利用dfs递归会好写很多。当然还是顺推,逆推写不出。
具体实现的时候有很多妙方法优化复杂度,在代码里面可以体现。
变进制数也可以像二进制一样O(1)转移,非常方便。
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#define int long long
using namespace std;
inline int r()
{
int s=0,k=1;char c=getchar();
while(!isdigit(c))
{
if(c=='-')k=-1;
c=getchar();
}
while(isdigit(c))
{
s=s*10+c-'0';
c=getchar();
}
return s*k;
}
string s;
int d;
int n,t,a[101],b[101],f[3700000],jc[101],pl[1001];
int dfs(int x)
{
if(f[x]<1e18)return f[x];
int th,tmp1;
for(int i=0;i<n;i++)//合并第i个
{
if(i>0&&pl[i]==0)continue;//已经被合并
for(int j=i+1;j<n;j++)//和第j个
{
if(pl[j]==0)continue;//已经被合并
int p1=pl[i],p2=pl[j];//回溯用
int a1=a[i],a2=a[j];
int tmp2=d;
th=x;
th-=pl[j]*j;
th-=pl[i]*i;
pl[i]+=pl[j];pl[j]=0;
th+=pl[i]*i;//新的排列
d-=a[i]*a[i];
d-=a[j]*a[j];
a[i]+=a[j];a[j]=0;
d+=a[i]*a[i];
tmp1=d;//这次合并之后的代价
f[x]=min(f[x],dfs(th)+tmp1);
a[i]=a1;a[j]=a2;
pl[i]=p1;pl[j]=p2;
d=tmp2;
}
}
return f[x];
}
signed main()
{
t=r();
int x;jc[0]=1;
for(int i=1;i<=10;i++)
jc[i]=jc[i-1]*i;
while(t--)
{
memset(f,0x7f,sizeof(f));
n=r();
d=0;
for(int i=1;i<=n;i++)
{
x=r();
cin>>s;
if(s=="8B0012")x=-x;
a[i-1]=x;
d+=a[i-1]*a[i-1];
pl[i-1]=jc[i-1];
}
f[0]=0;
cout<<dfs(jc[n]-1)<<endl;
}
}
本文来自博客园,作者:lei_yu,转载请注明原文链接:https://www.cnblogs.com/lytql/p/15058043.html