题解 P3959 宝藏

Posted zdsrs060330

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了题解 P3959 宝藏相关的知识,希望对你有一定的参考价值。

本来想好到csp之前就不写题解了

结果看了篇题解——

这个神仙解法我吹爆!

如果觉得我的解释不够清晰,可以看这篇博客


蒟蒻只会dfs

参考这位的70分做法

$w_{i,j}$读入的时候就要存好

用vis数组保存当前是否访问过,dep保存离根点数+1。

爆搜,爆搜。

#include <bits/stdc++.h>
using namespace std;
const int inf=0x3f3f3f3f;
int n,m,ans=inf,sum; 
bool vis[15];
int dep[15],w[15][15];
void dfs(int step){
	if(step==n){
		ans=min(ans,sum);
		return;
	}
	if(sum>=ans) return;
	for(int i=1;i<=n;i++){
		if(vis[i]) continue;//下一个挖开的宝藏屋 
		for(int j=1;j<=n;j++){
			if(i==j||vis[j]==0) continue;//出发点 
			if(w[i][j]==inf) continue;
			sum+=dep[j]*w[i][j];vis[i]=1;dep[i]=dep[j]+1;
			dfs(step+1);
			sum-=dep[j]*w[i][j];vis[i]=0;dep[i]=0;
		}
	}
}
int main() {
	scanf("%d%d",&n,&m);
	for(int i=1;i<=n;i++)
		for(int j=1;j<=n;j++)
			w[i][j]=inf;
	for(int i=1;i<=m;i++){
		int a,b,c;
		scanf("%d%d%d",&a,&b,&c);
		w[a][b]=w[b][a]=min(w[a][b],c);
	}
	for(int i=1;i<=n;i++){
		vis[i]=1;dep[i]=1;sum=0;
		dfs(1);
		vis[i]=0;dep[i]=0;
	}
	printf("%d
",ans);
	return 0;
}

n范围极小,状压。

dfs+状压DP

其实就是用dfs来实现状压DP的转移吧

$f_i$表示达到该种情况下最小代价

$dis_i$表示赞助商帮你打通的宝藏屋到第i个宝藏屋所经过的宝藏屋的数量

  • 枚举从每个点出发的情况

  • dfs+状压 暴力更新

这个思路简洁明了。

#include <bits/stdc++.h>
using namespace std;
const int inf=0x3f3f3f3f;
const int N=15;//这样写代码看着比较舒服
int n,m,ans=inf;
int dis[N],w[N][N],f[1<<N]; 
void dfs(int s){
	for(int i=1;i<=n;i++){
		if(s&(1<<(i-1))){//该屋已经被挖开了
			for(int j=1;j<=n;j++){
				if(!((1<<(j-1))&s)&&w[i][j]!=inf){//该屋没被挖开且可以到达
					if(f[s+(1<<(j-1))]>f[s]+w[i][j]*dis[i]){//接下来是更新
						int tmp=dis[j];//保存,待会儿要回溯
						dis[j]=dis[i]+1;
						f[s+(1<<(j-1))]=f[s]+w[i][j]*dis[i];//更新
						dfs(s+(1<<(j-1)));
						dis[j]=tmp;//回溯
					}
				}
			}
		}
	}
}
int main() {
	scanf("%d%d",&n,&m);
	for(int i=1;i<=n;i++)
		for(int j=1;j<=n;j++)
			w[i][j]=inf;
	for(int i=1;i<=m;i++){
		int a,b,c;
		scanf("%d%d%d",&a,&b,&c);
		w[a][b]=w[b][a]=min(w[a][b],c);//预处理
	}
	for(int i=1;i<=n;i++) dis[i]=inf; 
	for(int k=1;k<=n;k++){
		for(int i=1;i<=(1<<n)-1;i++)
			f[i]=inf;
		dis[k]=1;
		f[(1<<(k-1))]=0;
		dfs(1<<(k-1));
		ans=min(ans,f[(1<<n)-1]);
	}
	printf("%d
",ans);
	return 0;
}

以上是关于题解 P3959 宝藏的主要内容,如果未能解决你的问题,请参考以下文章

luogu P3959 宝藏

P3959 [NOIP2017 提高组] 宝藏

P3959 宝藏

P3959 宝藏

P3959 宝藏 状压dp

Luogu P3959 宝藏