1. 程式人生 > 實用技巧 >P1875 佳佳的魔法藥水

P1875 佳佳的魔法藥水

題目背景

發完了 k 張照片,佳佳卻得到了一個壞訊息:他的 MM 得病了!佳佳和大家一樣焦急 萬分!治好 MM 的病只有一種辦法,那就是傳說中的 0 號藥水 ……怎麼樣才能得到 0 號藥 水呢?你要知道佳佳的家境也不是很好,成本得足夠低才行……

題目描述

得到一種藥水有兩種方法:可以按照魔法書上的指導自己配置,也可以到魔法商店裡去 買——那裡對於每種藥水都有供應,雖然有可能價格很貴。在魔法書上有很多這樣的記載:

1 份 A 藥水混合 1 份 B 藥水就可以得到 1 份 C 藥水。(至於為什麼 1+1=1,因為……這是魔 法世界)好了,現在你知道了需要得到某種藥水,還知道所有可能涉及到的藥水的價格以及 魔法書上所有的配置方法,現在要問的就是:1.最少花多少錢可以配製成功這種珍貴的藥水;

2.共有多少種不同的花費最少的方案(兩種可行的配置方案如果有任何一個步驟不同則視為 不同的)。假定初始時你手中並沒有任何可以用的藥水。

輸入格式

第一行有一個整數 N(N<=1000),表示一共涉及到的藥水總數。藥水從 0~N­1 順序編號,0 號藥水就是 最終要配製的藥水。

第二行有 N 個整數,分別表示從 0~N­1 順序編號的所有藥水在魔法商店的價格(都表示 1 份的價格)。

第三行開始,每行有 3 個整數 A、B、C,表示 1 份 A 藥水混合 1 份 B 藥水就可以得到 1 份 C 藥水。注意,某兩種特定的藥水搭配如果能配成新藥水的話,那麼結果是唯一的。也就是 說不會出現某兩行的 A、B 相同但 C 不同的情況。

輸入以一個空行結束。

輸出格式

輸出兩個用空格隔開的整數,分別表示得到 0 號藥水的最小花費以及花費最少的方案的個 數。

輸入輸出樣例

輸入 #1
7 
10 5 6 3 2 2 3 
1 2 0 
4 5 1 
3 6 2
輸出 #1
10 3

說明/提示

樣例說明:

最優方案有 3 種,分別是:直接買 0 號藥水;買 4 號藥水、5 號藥水配製成 1 號藥水,直接 買 2 號藥水,然後配製成 0 號藥水;買 4 號藥水、5 號藥水配製成 1 號藥水,買 3 號藥水、6 號藥水配製成 2,然後配製成 0。

我是看這題和我名字像才做的

可以說是深搜也可以說是樹型dp,回想一下小學學的乘法原理

a和b藥水是組成c藥水選擇的最優之一,那麼c的方案數需要加上合成a的方案數乘上合成b的方案數

 1 #include <bits/stdc++.h>
 2 using namespace std;
 3 const int maxn=1000+5;
 4 int n,a[maxn],x,y,z,f[maxn],head[maxn],cnt;
 5 bool vis[maxn];
 6 struct Edge{
 7     int x,y,next;
 8 }e[maxn*maxn];
 9 void add(int x,int y,int z) {
10     e[++cnt].x=x;
11     e[cnt].y=y;
12     e[cnt].next=head[z];
13     head[z]=cnt;
14 }
15 void dp(int u) {
16     vis[u]=1;
17     for(int i=head[u];i;i=e[i].next) {
18         int x=e[i].x,y=e[i].y;
19         if(!vis[x]) dp(x);
20         if(!vis[y]) dp(y);
21         if(a[x]+a[y]<a[u]) {
22             a[u]=a[x]+a[y];
23             f[u]=f[x]*f[y];
24         }
25         else if(a[x]+a[y]==a[u]) {
26             f[u]+=f[x]*f[y];
27         }
28     }
29 }
30 int main() {
31     scanf("%d",&n);
32     for(int i=0;i<n;i++) {
33         scanf("%d",&a[i]);
34         f[i]=1;
35     }
36     while(scanf("%d%d%d",&x,&y,&z)==3) add(x,y,z);
37     dp(0);
38     printf("%d %d\n",a[0],f[0]);
39     return 0;
40 }