LG 3959 宝藏

状压DP

蒟蒻想了个\(O(N^3\ast 3^N)\)

膜拜SZR博客之后
才知道怎么优化掉一个N
码力同翔
1.5h才过样例

SZR's blog

#include <iostream>
#include <cassert>

using namespace std;

const long long LONF=4567891012345678910LL;
const int INF=1034567890;
const int MAXN=13;
const int MAXM=4111;

int N, M;
long long Map[MAXN][MAXN];
long long F[MAXN][MAXN][MAXM];
int Cnt[MAXM];
int Mat[MAXN][MAXN][MAXM];
long long MinC, Cost;

long long lmin(long long a, long long b){
	return (a>b)?b:a;
}

int main(){
	ios_base::sync_with_stdio(false);
	
	cin >> N >> M;
	for(int i=0;i<N;++i)
		for(int j=0;j<N;++j)
			Map[i][j]=(long long)(INF);
	for(int i=0;i<N;++i)	Map[i][i]=0LL;
	for(int i=1, a, b, v;i<=M;++i){
		cin >> a >> b >> v;--a;--b;
		Map[a][b]=lmin(Map[a][b], (long long)(v));
		Map[b][a]=lmin(Map[b][a], (long long)(v));
	}
	
	M=(1<<N);
	
	for(int i=0;i<=N;++i)
		for(int j=0;j<=N;++j)
			for(int p=0;p<M;++p)
				F[i][j][p]=LONF, Mat[i][j][p]=-1;
	
	for(int i=0, k;i<M;++i){
		k=i;Cnt[i]=0;
		while(k>0){
			if(k&1)	++Cnt[i];
			k>>=1;
		}
	}
	
	for(int s=1, i=0;s<M;s<<=1, ++i){
		for(int j=0;j<N;++j){
			F[i][j][s]=0LL;
		}
		for(int j=0;j<N;++j){
			if(j==i)	continue;
			for(int d=0;d<N;++d){
				Mat[j][d][s]=i;
			}
		}
	}
	
	for(int s=1;s<M;++s){
		if(Cnt[s]<=1)	continue;
		for(int ss=(s-1)&s, iss;ss>0;ss=(ss-1)&s){
			iss=s-ss;
			for(int d=0;d+Cnt[s]<=N;++d){
				for(int i=0, j;i<N;++i){
					if(((1<<i)&ss)==0)	continue;
					j=Mat[i][d][iss];
					//cout << i << " " << d << " " << iss << endl;
					assert(j>-1 && j<N);
					//cout << "(" << i << "," << d << "," << s << ")<-(" << j << "," << d+1 << "," << iss << ")" << endl;
					F[i][d][s]=lmin(F[i][d][s], F[i][d][ss]+Map[i][j]*(long long)(d+1)+F[j][d+1][iss]);
				}
			}
		}
		for(int i=0;i<N;++i){
			if(((1<<i)&s)!=0)	continue;
			for(int d=0;d+Cnt[s]<=N;++d){
				Mat[i][d][s]=-1;MinC=LONF;
				for(int j=0;j<N;++j){
					if(((1<<j)&s)==0)	continue;
					Cost=F[j][d+1][s]+Map[i][j]*(long long)(d+1);
					if(Cost<MinC){
						MinC=Cost;Mat[i][d][s]=j;
					}
				}
			}
		}
	}
	
	/*
	for(int s=1;s<M;++s){
		for(int i=0;i<N;++i){
			if(((1<<i)&s)==0)	continue;
			for(int d=0;d+Cnt[s]<=N;++d){
				cout << i << " " << d << " " << s << " " << F[i][d][s] << endl;
			}
		}
	}
	*/
	
	long long ANS=LONF;
	for(int i=0;i<N;++i)
		ANS=lmin(ANS, F[i][0][M-1]);
	cout << ANS << endl;
	
	return 0;
}

posted @ 2018-04-01 22:33  Pickupwin  阅读(156)  评论(0编辑  收藏  举报