佳佳的魔法药水
P1875
技术统计
难度 提高+/省选-
用时
50min
提交次数 5
unaccept 次数 4
ac次数 1
题意概括
求一个路径和的最小值
数据范围
n ≤ 1000 n\le1000 n≤1000
解法、
知识点
- dfs
- 递归
- 树形结构
- 乘法原理
- 加法原理
解法概括
对于每一个节点,我们比较直接去买和间接去配制哪一个的花费更小。若二者相等或直接买比间接配制成本更低,那么根据加法原理,方案数+=左儿子的方案数右儿子的方案数;否则根据乘法原理方案数=左儿子的方案数*右儿子的方案数。
坑点
- 一定要先去dfs下一层再去计算方案和最小花费
- 这不一定是一棵二叉树,图中可能存在环,所以需要记vis[i]来判断该节点是否搜过
代码实现
#include<cstdio>
using namespace std;
struct edge
{
int nxt,ls,rs;
}p[1000100];
int n,cnt;
int w[10100],head[10100],sum[10100];
bool vis[10100];
inline int read()
{
int f=1,k=0;
char c=getchar();
while(c>'9'||c<'0')
{
if(c=='-')f=-1;
c=getchar();
}
while(c<='9'&&c>='0')k=(k<<1)+(k<<3)+(c^48),c=getchar();
return f*k;
}
void dfs(int now)
{
for(int i=head[now];i;i=p[i].nxt)
{
int x=p[i].ls,y=p[i].rs;
vis[now]=1;
if(!vis[x])dfs(x);
if(!vis[y])dfs(y);
if(w[x]+w[y]<w[now])
{
w[now]=w[x]+w[y];
sum[now]=sum[x]*sum[y];
}
else
{
if(w[x]+w[y]==w[now])
sum[now]+=(sum[x]*sum[y]);
}
}
}
int main()
{
n=read();
for(int i=0;i<n;i++)w[i]=read(),sum[i]=1;
int a,b,c;
while(scanf("%d%d%d",&a,&b,&c)!=EOF)
{
p[++cnt].ls=a;
p[cnt].rs=b;
p[cnt].nxt=head[c];
head[c]=cnt;
}
dfs(0);
printf("%d %d",w[0],sum[0]);
return 0;
}