寶藏 洛谷p3959

2021-08-30 13:57:22 字數 3383 閱讀 8362

參與考古挖掘的小明得到了乙份藏寶圖,藏寶圖上標出了 nn 個深埋在地下的寶藏屋, 也給出了這 nn 個寶藏屋之間可供開發的mm 條道路和它們的長度。

小明決心親自前往挖掘所有寶藏屋中的寶藏。但是,每個寶藏屋距離地面都很遠, 也就是說,從地面打通一條到某個寶藏屋的道路是很困難的,而開發寶藏屋之間的道路 則相對容易很多。

小明的決心感動了考古挖掘的贊助商,贊助商決定免費贊助他打通一條從地面到某 個寶藏屋的通道,通往哪個寶藏屋則由小明來決定。

在此基礎上,小明還需要考慮如何開鑿寶藏屋之間的道路。已經開鑿出的道路可以 任意通行不消耗代價。每開鑿出一條新道路,小明就會與考古隊一起挖掘出由該條道路 所能到達的寶藏屋的寶藏。另外,小明不想開發無用道路,即兩個已經被挖掘過的寶藏 屋之間的道路無需再開發。

新開發一條道路的代價是:

\mathrm \times \mathrml×k

l代表這條道路的長度,k代表從贊助商幫你打通的寶藏屋到這條道路起點的寶藏屋所經過的 寶藏屋的數量(包括贊助商幫你打通的寶藏屋和這條道路起點的寶藏屋) 。

請你編寫程式為小明選定由贊助商打通的寶藏屋和之後開鑿的道路,使得工程總代 價最小,並輸出這個最小值。

輸入格式:

第一行兩個用空格分離的正整數 n,mn,m,代表寶藏屋的個數和道路數。

接下來 mm 行,每行三個用空格分離的正整數,分別是由一條道路連線的兩個寶藏 屋的編號(編號為 1-n1−n),和這條道路的長度 vv。

輸出格式:

乙個正整數,表示最小的總代價。

輸入樣例#1:複製

4 5 

1 2 1

1 3 3

1 4 1

2 3 4

3 4 1

輸出樣例#1:複製

4
輸入樣例#2:複製

4 5 

1 2 1

1 3 3

1 4 1

2 3 4

3 4 2

輸出樣例#2:複製

【樣例解釋1】

小明選定讓贊助商打通了11 號寶藏屋。小明開發了道路 1 \to 21→2,挖掘了 22 號寶 藏。開發了道路 1 \to 41→4,挖掘了 44號寶藏。還開發了道路 4 \to 34→3,挖掘了33號寶 藏。工程總代價為:1 \times 1 + 1 \times 1 + 1 \times 2 = 41×1+1×1+1×2=4

【樣例解釋2】

小明選定讓贊助商打通了11 號寶藏屋。小明開發了道路 1 \to 21→2,挖掘了 22 號寶 藏。開發了道路 1 \to 31→3,挖掘了 33號寶藏。還開發了道路 1 \to 41→4,挖掘了44號寶 藏。工程總代價為:1 \times 1 + 3 \times 1 + 1 \times 1 = 51×1+3×1+1×1=5

【資料規模與約定】

對於20\%20%的資料: 保證輸入是一棵樹,1 \le n \le 81≤n≤8,v \le 5000v≤5000 且所有的 vv都相等。

對於 40\%40%的資料: 1 \le n \le 81≤n≤8,0 \le m \le 10000≤m≤1000,v \le 5000v≤5000 且所有的vv都相等。

對於70\%70%的資料: 1 \le n \le 81≤n≤8,0 \le m \le 10000≤m≤1000,v \le 5000v≤5000

對於100\%100%的資料: 1 \le n \le 121≤n≤12,0 \le m \le 10000≤m≤1000,v \le 500000v≤500000

解法一:隨機化貪心,用類似prim的演算法每次選偽最優解擴充套件。

#include#define f(i,l,r) for(i=(l);i<=(r);i++)

using namespace std;

const int maxn=15,maxm=1005,inf=1e9;

struct edgee[maxm<<1];

int dep[maxn],dis[maxn][maxn];

struct node

};int h[maxn],tot;

int n,m,vis[maxn];

inline void add(int u,int v,int w)

; h[u]=tot++;

}namespace task1

max_size=max(max_size,n-size[u]);

if(max_sizeinf||dis[j][k]>inf) continue;

dis[i][j]=dis[j][i]=min(dis[i][j],dis[i][k]+dis[j][k]);}}

} f(i,1,n)

ans=min(ans,tmp);

} cout

queuep;

q.push((node));

f(i,1,n)

vis[u]=1;

res+=tmp.d;

while(!p.empty())

dep[u]=dep[tmp.u]+1;

f(j,1,n));

} }return res;

}int main()

if(m==n-1)

memset(dis,60,sizeof(dis));

f(u,1,n)

} if(flag)

int t=600;

while(t--)

} cout解法二:狀壓dp。f[s]表示狀態為s時的最小花費,轉移時列舉i,j,從i往j建路,並記錄深度dep[j]=dep[i]+1。

#include#define f(i,l,r) for(i=(l);i<=(r);i++)

using namespace std;

const int maxn=15,inf=1e9;

int a[maxn][maxn];

int n,m;

int f[1<<12],dep[maxn];

void dfs(int sta)

f(i,0,n-1)

int all=(1<=inf) continue;

g[i][j]=min(g[i][j],g[i-1][k]+i*f[k][j]);

}} }

f(i,0,n-1)

cout<

return 0;

}

P3959 寶藏 模擬退火。。。

竟然模擬退火能做!我就直接抄 了,我加了點注釋。題幹 題目描述 參與考古挖掘的小明得到了乙份藏寶圖,藏寶圖上標出了 nn 個深埋在地下的寶藏屋,也給出了這 nn 個寶藏屋之間可供開發的 mm 條道路和它們的長度。小明決心親自前往挖掘所有寶藏屋中的寶藏。但是,每個寶藏屋距離地面都很遠,也就是說,從地面...

P3959 寶藏 狀壓dp

之前寫了乙份此題關於模擬退火的方法,現在來補充一下狀壓dp的方法。其實直接在dfs中狀壓比較好想,而且實現也很簡單,但是網上有人說這種方法是錯的。並不知道哪錯了,但是就不寫了,找了乙個正解。正解的區別在於狀態,樹高是啥意思 每次都是從當前狀態的子集轉移過來。這裡用到了快速列舉子集的操作,很值得寫一下...

P3959 寶藏(狀壓 dp)

一任意乙個節點為根,每連線乙個新的節點需要花費 dep dis dis 為相鄰兩節點的距離,求最小花費,根的深度為 0 1 n 12 1 m 3000 1 5 10 5 4 5 1 2 1 1 3 3 1 4 1 2 3 4 3 4 14如果可以想出 dp 方程還是很好解決的,dp i j 表示深度...