洛谷P3959 寶藏【狀壓DP】
時空限制 1000ms / 256MB
題目描述
參與考古挖掘的小明得到了一份藏寶圖,藏寶圖上標出了 nn 個深埋在地下的寶藏屋, 也給出了這 nn 個寶藏屋之間可供開發的 mm 條道路和它們的長度。
小明決心親自前往挖掘所有寶藏屋中的寶藏。但是,每個寶藏屋距離地面都很遠, 也就是說,從地面打通一條到某個寶藏屋的道路是很困難的,而開發寶藏屋之間的道路 則相對容易很多。
小明的決心感動了考古挖掘的贊助商,贊助商決定免費贊助他打通一條從地面到某 個寶藏屋的通道,通往哪個寶藏屋則由小明來決定。
在此基礎上,小明還需要考慮如何開鑿寶藏屋之間的道路。已經開鑿出的道路可以 任意通行不消耗代價。每開鑿出一條新道路,小明就會與考古隊一起挖掘出由該條道路 所能到達的寶藏屋的寶藏。另外,小明不想開發無用道路,即兩個已經被挖掘過的寶藏 屋之間的道路無需再開發。
新開發一條道路的代價是:
L代表這條道路的長度,K代表從贊助商幫你打通的寶藏屋到這條道路起點的寶藏屋所經過的 寶藏屋的數量(包括贊助商幫你打通的寶藏屋和這條道路起點的寶藏屋) 。
請你編寫程式為小明選定由贊助商打通的寶藏屋和之後開鑿的道路,使得工程總代 價最小,並輸出這個最小值。
輸入格式:
第一行兩個用空格分離的正整數 n,mn,m,代表寶藏屋的個數和道路數。
接下來 mm 行,每行三個用空格分離的正整數,分別是由一條道路連線的兩個寶藏 屋的編號(編號為 1-n1−n),和這條道路的長度 vv。
輸出格式:
一個正整數,表示最小的總代價。
【資料規模與約定】
對於 的資料: 保證輸入是一棵樹,, 且所有的都相等。
對於 的資料:,, 且所有的 都相等。
對於 的資料: ,, 對於 的資料:,,
NOIP2018賽前兩個月 回首2017爆零的噩夢
題目分析
感覺還是叫狀壓暴搜比較合適 表示達到狀態x所需最小化費 記錄當前狀態下從起點到u經過的寶藏屋數量
列舉每個點u作為起點
假設當前x所表示的狀態中 所有已到達的點為,未到達的點為 對於同一個,可能同時存在多個個可以到達他 怎麼辦?其實就試著從每個到搜一次就好了
也就是先令,同時更新 然後向下一狀態搜尋 回溯後再把改回原來的值
所以說就是加了狀壓的暴搜啊
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<queue>
#include<vector>
using namespace std;
typedef long long lt;
int read()
{
int x=0,f=1;
char ss=getchar();
while(ss<'0'||ss>'9'){if(ss=='-')f=-1;ss=getchar();}
while(ss>='0'&&ss<='9'){x=x*10+ss-'0';ss=getchar();}
return x*f;
}
const int inf=1128481603;
const int maxn=8010;
int n,m;
int rem[20][20];
int dp[maxn],dis[20],ans=1e9;
void dfs(int x)
{
for(int i=1;i<=n;++i)//列舉當前已挖過的寶藏屋
if((1<<i-1)&x)
for(int j=1;j<=n;++j)//列舉還沒有挖過的寶藏屋
if( rem[i][j]!=inf && ((1<<j-1)&x)==0 )
{
if(dp[x|(1<<j-1)]>dp[x]+rem[i][j]*dis[i])//能更新下一狀態最優解才向下搜尋
{
int tt=dis[j];
dis[j]=dis[i]+1;
dp[x|(1<<j-1)]=dp[x]+rem[i][j]*dis[i];
dfs(x|(1<<j-1));
dis[j]=tt;//記得改回來
}
}
}
int main()
{
n=read();m=read();
memset(rem,67,sizeof(rem));
for(int i=1;i<=m;++i)
{
int u=read(),v=read(),dis=read();
rem[u][v]=min(rem[u][v],dis);
rem[v][u]=min(rem[v][u],dis);
}
for(int i=1;i<=n;++i)//列舉每個點作起點
{
memset(dp,67,sizeof(dp));
memset(dis,67,sizeof(dis));
dis[i]=1; dp[1<<(i-1)]=0;
dfs(1<<(i-1));
ans=min(ans,dp[(1<<n)-1]);
}
printf("%lld",ans);
return 0;
}