菌落 [状压dp?]

菌落


\color{blue}{最初想法}

对题目中要求的不同颜色, 可以通过正负号来区分, 操作时直接相加即可,

  • F[i,s]F[i, s] 表示前 ii 天, 状态为 ss 的最小花费, ss是一个0/10/1串,
  • A[i,s,k]A[i, s, k] 表示前 ii 天, 状态为 ss, 第 kk 个位置的值 .

:初值 : F[0,(1<<N)1]=0F[0, (1<<N)-1] = 0, 其余为 infinf .

F[i,s]F[i, s] 能够更新以下状态

  • F[i,s xor (1<<j1)]=min(F[i1,s]+cost)F[i, s\ xor\ (1<<j-1)]=\min(F[i-1, s]+cost)
  • F[i,s xor (1<<k1)]=min(F[i1,s]+cost)F[i, s\ xor\ (1<<k-1)]=\min(F[i-1, s]+cost)

其中 jjkk 为枚举的 决策, 具体地说, 表示 jjkk 位置上的数字合并, 且重新放在 jj 或者 kk 位置上 .
A[]A[] 数组的更新就不在多说了 .

为什么会错啊啊啊啊!!!

#include<bits/stdc++.h>
#define reg register
typedef long long ll;

const ll inf = 10000000000000015;

int read(){
        char c;
        int s = 0, flag = 1;
        while((c=getchar()) && !isdigit(c))
                if(c == '-'){ flag = -1, c = getchar(); break ; }
        while(isdigit(c)) s = s*10 + c-'0', c = getchar();
        return s * flag;
}

int N;
ll B[12];
ll A[12][1029][12];

ll F[12][1029];

char tmp_s[10];

void Work(){
        N = read();
        for(reg int i = 1; i <= N; i ++){
                B[i] = read();
                scanf("%s", tmp_s);
                if(tmp_s[0] == '8') B[i] = -B[i];
        }

        std::reverse(B+1, B+N+1);
        for(reg int i = 1; i <= N; i ++) A[0][(1<<N)-1][i] = B[i];
        
        for(reg int i = 0; i <= N; i ++)
                for(reg int j = 0; j < 1<<N; j ++) F[i][j] = inf;
        F[0][(1<<N)-1] = 0;
        srand(19260817);
        for(reg int i = 1; i < N; i ++)
                for(reg int s = (1<<N)-1; s >= 0; s --){
                	if(F[i-1][s] == inf) continue ;
                        for(reg int j = 1; j <= N; j ++){
                                if(!(s & (1<<j-1))) continue ;
                                for(reg int k = j+1; k <= N; k ++){
                                        if(k == j || !(s & (1<<k-1))) continue ;
                                        ll &t = F[i][s^(1<<j-1)];
                                        
                                        for(reg int p = 1; p <= N; p ++) B[p] = A[i-1][s][p];
                                        B[j] = 0, B[k] = A[i-1][s][j] + A[i-1][s][k];                                    
                                        ll cost = 0;
                                        int zt = s^(1<<j-1);
                                        for(reg int p = 1; p <= N; p ++)
                                        	if(zt & (1<<p-1)) cost += 1ll*B[p]*B[p];
                                        ll tmp = F[i-1][s] + cost;
                                        
                                        if(t > tmp || (rand()%2 == 0 && t == tmp)){
                                                t = tmp;
                                                for(reg int p = 1; p <= N; p ++) A[i][zt][p] = A[i-1][s][p];
                                                A[i][zt][j] = 0;
                                                A[i][zt][k] = A[i-1][s][j] + A[i-1][s][k];
                                        }
                                                                                
                                        ll &t2 = F[i][s^(1<<k-1)];
                                        if(t2 > tmp || (rand()%2 == 0 && t2 == tmp)){
                                                t2 = tmp;
                                                zt = s^(1<<k-1);
                                                for(reg int p = 1; p <= N; p ++) A[i][zt][p] = A[i-1][s][p];
                                                A[i][zt][k] = 0;
                                                A[i][zt][j] = A[i-1][s][j] + A[i-1][s][k];
                                        }
                                }
                        }
                }
        ll Ans = inf;
        for(reg int i = 0; i < N; i ++) Ans = std::min(Ans, F[N-1][1<<i]);
        printf("%lld\n", Ans);
}

int main(){
	freopen("germ.in", "r", stdin);
	freopen("germ.out", "w", stdout);
        int T = read();
        while(T --) Work();
        return 0;
}

\color{red}{正解部分}

404 Not Found


\color{red}{实现部分}

404 Not Found

#include<bits/stdc++.h>
using namespace std;
int n,t,fac[15],tri[15];
long long a[15],f[3628805],F,d,tp[15];
char s[15];

long long dfs(int x){
	if(f[x]!=1e18) return f[x];
	int th;
	long long dd;
	for(int i=0;i<n;i++){
		if(tri[i]==0&&i>0) continue;
		for(int j=i+1;j<n;j++){
			if(tri[j]==0) continue;
			int t1=tri[i],t2=tri[j];
			long long t3=tp[i],t4=tp[j];
			long long ddd=d;
			th=x;th-=tri[j]*j+tri[i]*i;
			tri[i]=tri[i]+tri[j];
			tri[j]=0;th+=tri[i]*i;
			d-=tp[i]*tp[i]+tp[j]*tp[j];
			tp[i]=tp[i]+tp[j];
			tp[j]=0;d+=tp[i]*tp[i];
			dd=d;
			f[x]=min(f[x],dfs(th)+dd);
			tri[i]=t1,tri[j]=t2;
			tp[i]=t3,tp[j]=t4;
			d=ddd;
		}
	}
	return f[x];
}

int main(){
	freopen("germ.in","r",stdin);
	freopen("germ.out","w",stdout);
	scanf("%d",&t);
	fac[0]=1;
	for(int i=1;i<=10;i++) fac[i]=i*fac[i-1];
	f[0]=0;
	while(t--){
		scanf("%d",&n);
		F=d=0;
		for(int i=1;i<=n;i++){
			scanf("%lld %s",&a[i],s+1);
			if(s[1]=='8') a[i]=-a[i];
			F+=(i-1)*fac[i-1];
			tri[i-1]=fac[i-1];
			tp[i-1]=a[i];
			d+=tp[i-1]*tp[i-1];
		}
		for(int i=1;i<=3628800;i++) f[i]=1e18; 
		printf("%lld\n",dfs(F));
	}
	
	return 0;
}
posted @ 2019-07-26 19:20  XXX_Zbr  阅读(140)  评论(0编辑  收藏  举报