【題解】洛谷P3959 [NOIP2017TG] 寶藏(狀壓DP+DFS)
阿新 • • 發佈:2018-11-08
洛谷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; }