1. 程式人生 > >【題解】洛谷P3959 [NOIP2017TG] 寶藏(狀壓DP+DFS)

【題解】洛谷P3959 [NOIP2017TG] 寶藏(狀壓DP+DFS)

洛谷P3959:https://www.luogu.org/problemnew/show/P3959

前言

NOIP2017時還很弱(現在也很弱

看出來是DP 但是並不會狀壓DP

現在看來思路並不複雜 只是存狀態有點難想到

思路

因為n最大為12

所以可以想到是狀壓

 

程式碼

#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
#define INF 1e9+7
int n,m,ans=INF;
int f[8000],h[15
],dis[15],map[15][15];//dis為題目中的k 即經過了幾個寶藏 bool vis[15][15]; void dfs(int s) { for(int i=1;i<=n;i++) { if(s&(1<<(i-1)))//尋找已經挖通的寶藏 for(int j=1;j<=n;j++)//列舉下一個寶藏 { if(!(s&(1<<(j-1)))&&vis[i][j]&&f[1<<(j-1
)|s]>f[s]+dis[i]*map[i][j]) {//如果沒有挖過j 且i與j之間有路徑 且有一個更優解 int k=dis[j];//記錄原dis方便後面回溯 dis[j]=dis[i]+1;//記錄新的dis f[1<<(j-1)|s]=f[s]+dis[i]*map[i][j];//更新更優解 dfs(s|1<<(j-1)); dis[j]=k;//回溯 } } } }
int main() { cin>>n>>m; memset(map,INF,sizeof(map));//矩陣賦值最大值 for(int i=1;i<=m;i++) { int x,y,z; cin>>x>>y>>z; if(z<map[x][y])//取最小的一條路 { map[x][y]=z; map[y][x]=z; vis[x][y]=1;//判斷是否存在路徑 vis[y][x]=1; } } for(int i=1;i<=n;i++)//列舉每個點為起點 { memset(dis,INF,sizeof(dis));//初始化 memset(f,INF,sizeof(f)); dis[i]=1;//起點經過的點有1個 f[1<<(i-1)]=0;//當前狀態的最小值 dfs(1<<(i-1));//搜尋 ans=min(ans,f[(1<<n)-1]);//狀態滿的時候取最小值 } cout<<ans; }