P3959 [NOIP2017 提高组] 宝藏
P3959 [NOIP2017 提高組] 寶藏
題意:
額題意不好說,就是n個點m個邊,選定一個點為根節點,構造一個最小生成樹,邊的權值為該該邊起點到根節點之間的點的數量K(不含根節點) * 道路長度
1<=n<=12
0<=m<=1e3
v<=5e5
題解:
參考題解
這數據范圍?暴力暴力暴力
不,我們用狀壓dp來做
我們設dp[i][j]表示用到第i個元素,當前連接狀態為j的花費的最小值
這個式子沒辦法直接轉移,因為每個邊的花費是不一樣的,即k是不一樣的,我們可以重新設計一個狀態,我們將k值理解為距離初始化點的層數,如圖
被涂藍色的就是根節點,k就是劃分的層數
這樣我們設dp[i][j]表示到第i層,總共取了的點的狀態為j
轉移為:
dp[i][j] = min(dp[i-1][k]+trans[k][j] * (i-1))
trans[k][j] * (i-1)就是題目說的距離 * K(題目中說的k)
k是j的子集,即有可能轉移到j的狀態
trans[k][j]表示從狀態k轉移到狀態j的最小花費路徑
這個子集意思就是:sub就是S的子集
這個子集怎么求??
直接求2^n必然不行,會T,有小技巧
由公式:
證明過程
最終答案就是:min(dp[i][2n-1])
初始化:dp[1][2(i-1)] = 0 (i∈[1,n])
我感覺代碼很妙,思路也很妙,讓我想是真寫不出來
我詳細說trans如何求:
現在i是當前狀態,j是i的子狀態,我們現在要狀態轉移從j–>i
temp=i ^ j,即要轉移的點(因為 ^ 為不同為1)
然后我們開始枚舉temp中存在的點k(從高位往低位),然后求從k到j的最短距離tmin,把tmin加入到trans[j][i]中
代碼:
#include<iostream> #include<cstdio> #include<cstring> using namespace std; long long read() {long long x=0,f=1; char c=getchar();while(!isdigit(c)){if(c=='-') f=-1;c=getchar();}while(isdigit(c)){x=x*10+c-'0';c=getchar();}return x*f; } const int N=12+2; const int M=1<<N; int n,m,dis[N][N],trans[M][M],POW[N]; long long f[N][M]; int main() {n=read(),m=read();memset(dis,0x3f,sizeof dis);for(int i=1;i<=m;i++){int s=read(),t=read(),v=read();if(dis[s][t]>v)dis[s][t]=dis[t][s]=v;}for(int i=0;i<(1<<n);i++)for(int j=i;j!=0;j=(j-1)&i){bool OK=true;int temp=i^j;//狀態i與狀態j的不同之處,狀態轉移為j->i for(int k=n-1;k>=0;k--){if((temp>>k)&1)//說明點k是轉移中增加的點,即 j沒有,i有 {int tmin=0x3f3f3f3f;for(int L=1;L<=n;L++)if(1&(j>>(L-1)))//如果狀態j包含此點 ,求出L到k+1的最短距離//if(((1<<(L-1))&j)==(1<<(L-1))) tmin=min(tmin,dis[L][k+1]);if(tmin==0x3f3f3f3f)//如果此路無法走通 {OK=false;break;}trans[j][i]+=tmin;/*相當于把j到i這段路拆分成了好幾份 */ temp-=(1<<k);}}if(OK==false)trans[j][i]=0x3f3f3f3f;}memset(f,0x3f,sizeof f);for(int i=1;i<=n;i++)f[1][(1<<(i-1))]=0;for(int i=2;i<=n;i++)for(int j=0;j<(1<<n);j++)for(int k=j;k!=0;k=(k-1)&j)//k為j的子狀態,也就是k是j的子集 if(trans[k][j]!=0x3f3f3f3f)//說明可以從狀態k到j f[i][j]=min(f[i][j],f[i-1][k]+(i-1)*trans[k][j]);long long ans=0x3f3f3f3f3f3f3f3fll;for(int i=1;i<=n;i++)ans=min(ans,f[i][(1<<n)-1]);printf("%lld",ans);return 0; }總結
以上是生活随笔為你收集整理的P3959 [NOIP2017 提高组] 宝藏的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 细胞角蛋白是什么意思
- 下一篇: 牛客网区间dp练习