P3959 [NOIP2017 提高組] 寶藏

rgw2010發表於2024-08-05

思路:

考慮狀態壓縮動態規劃。

定義 \(dp_{i,j,S}\) 表示點 \(j\) 離起點 \(i\) 的距離,且從點 \(j\) 開始打通的點集為 \(S\) 的最小代價(注意 \(S\) 不能包含 \(j\))。

考慮列舉 \(S\) 一個一個子集 \(S'\),同時列舉一個 \(k\),需要滿足 \(k \in S'\),即我們可以先打通 \(j \to k\),然後由 \(k\) 來打通 \(S'\),由 \(j\) 來打通 \(S \setminus S'\),則狀態轉移方程為:

\[dp_{i,j,S} = \min\limits_{k \in S' \subseteq S} W(i,k) \times (i+1) + dp_{i+1,k,S' \setminus \{k\}} + dp_{i,j,S \setminus S'} \]

時間複雜度為 \(O(3^nn^3)\)

注意要先預處理出每個子集狀態第一位為 \(1\) 的位置,方便列舉 \(k\),可以用 lowbit 實現。

完整程式碼:

#include<bits/stdc++.h>
#define Add(x,y) (x+y>=mod)?(x+y-mod):(x+y)
#define lowbit(x) x&(-x)
#define pi pair<ll,ll>
#define pii pair<ll,pair<ll,ll>>
#define iip pair<pair<ll,ll>,ll>
#define ppii pair<pair<ll,ll>,pair<ll,ll>>
#define fi first
#define se second
#define full(l,r,x) for(auto it=l;it!=r;it++) (*it)=x
#define Full(a) memset(a,0,sizeof(a))
#define open(s1,s2) freopen(s1,"r",stdin),freopen(s2,"w",stdout);
using namespace std;
typedef double db;
typedef unsigned long long ull;
typedef long long ll;
const ll N=12,M=(1ll<<N)+10,INF=1e9;
bool Begin;
inline ll read(){
    ll x=0,f=1;
    char c=getchar();
    while(c<'0'||c>'9'){
        if(c=='-')
          f=-1;
        c=getchar();
    }
    while(c>='0'&&c<='9'){
        x=(x<<1)+(x<<3)+(c^48);
        c=getchar();
    }
    return x*f;
}
inline void write(ll x){
	if(x<0){
		putchar('-');
		x=-x;
	}
	if(x>9)
	  write(x/10);
	putchar(x%10+'0');
}
ll n,m,u,v,w,ans=INF;
ll W[N][N],id[M];
ll dp[N][N][M];
bool End;
int main(){
//	open("A.in","A.out");
	n=read(),m=read();
	for(int i=0;i<n;i++)
	  for(int j=0;j<n;j++)
	    W[i][j]=INF;
	for(int i=0;i<n;i++)
	  for(int j=0;j<n;j++)
	    for(int k=1;k<(1ll<<n);k++)
	      dp[i][j][k]=INF;
	while(m--){
		u=read()-1,v=read()-1,w=read();
		W[u][v]=W[v][u]=min({W[u][v],w});
	}
	for(int x=1,i=0;i<n;i++){
		id[x]=i;
		x<<=1ll;
	}
	for(int i=n-2;i>=0;i--){
		for(int j=0;j<n;j++){
			for(int S=1;S<(1ll<<n);S++){
				if((S>>j)&1ll)
				  continue;		 
				for(int T=S;T;T=(T-1)&S){
					if(dp[i][j][S^T]>=dp[i][j][S])
					  continue;
					for(int G=T;G;G^=lowbit(G)){
						ll k=id[lowbit(G)];
						if(W[j][k]==INF||j==k)
						  continue;
						dp[i][j][S]=min(dp[i][j][S],W[j][k]*(i+1)+dp[i+1][k][T^(1ll<<k)]+dp[i][j][S^T]);						
					}
				}
			}
		}
	}
	for(int i=0;i<n;i++)
	  ans=min(ans,dp[0][i][((1ll<<n)-1)^(1ll<<i)]);
	write(ans);
	return 0;
}

相關文章