【vijos】【树形dp】佳佳的魔法药水
描述
得到一种药水有两种方法:可以按照魔法书上的指导自己配置,也可以到魔法商店里去买——那里对于每种药水都有供应,虽然有可能价格很贵。在魔法书上有很多这样的记载: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号药水的最小花费以及花费最少的方案的个数。
代码
#include <cstdio>
#include <cstring>
#include <vector>
#include <queue>
#define maxn 1100
using namespace std;
struct edge{
int a,b;
edge(int a=0,int b=0){
this->a=a; this->b=b;
}
};
struct node{
int num,dist;
node(int num=0,int dist=0){
this->num=num; this->dist=dist;
}
};
bool operator < (const node &a,const node &b){
if(a.dist==b.dist) return a.num>b.num;
else return a.dist>b.dist;
}
int n,c[maxn],dist[maxn],x,y,z,path[maxn];
vector<edge> g[maxn];
bool vis[maxn];
void dijkstra(){
priority_queue<node> q;
memset(vis,0,sizeof(vis));
for(int i=0;i<n;i++){
dist[i]=c[i];
path[i]=1;
q.push(node(i,dist[i]));
}
while(!q.empty()){
int cur=q.top().num; q.pop();
if(vis[cur]) continue;
else vis[cur]=true;
for(int i=0;i<(int)g[cur].size();i++){
int a=g[cur][i].a,b=g[cur][i].b;
if(vis[a]&&dist[b]>=dist[a]+dist[cur]){
q.push(node(b,dist[b]));
if(dist[b]==dist[a]+dist[cur]) path[b]+=path[a]*path[cur];
else path[b]=path[a]*path[cur];
dist[b]=dist[a]+dist[cur];
}
}
}
}
int main(){
//freopen("in.txt","r",stdin);
scanf("%d",&n);
for(int i=0;i<n;i++) scanf("%d",&c[i]);
while(scanf("%d%d%d",&x,&y,&z)==3){
g[x].push_back(edge(y,z));
if(x!=y) g[y].push_back(edge(x,z));
}
dijkstra();
printf("%d %d",dist[0],path[0]);
return 0;
}