參與考古挖掘的小明得到了乙份藏寶圖,藏寶圖上標出了 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 表示深度...