E. Nastya and Potions(DFS+记忆化搜索)

该问题描述了一个炼金术士通过混合不同药剂来获取新药剂的过程,每种药剂有特定的购买成本,已知一些药剂可以无限供应。任务是计算获得每种药剂的最低硬币数量。通过构建图并使用深度优先搜索(DFS)策略,可以找到每种药剂的最小成本路径。
摘要由CSDN通过智能技术生成

炼金术士纳斯蒂亚喜欢混合药剂。一共有n种药剂,ci硬币可以买到一种 i 型药剂。 任何一种药剂都只能通过一种方式获得,即混合其他几种药剂。混合过程中使用的药剂将被消耗掉。此外,任何药剂都不能通过一个或多个混合过程从自身获得。

作为一名经验丰富的炼金术士,Nastya拥有无限量的k种药剂p1、p2、…、pk,但她不知道下一步要获得哪一种。为了做出决定,她要求你为每1≤i≤n找到她下一次获得 i 型药剂所需的最低硬币数量。

输入:

每个测试的第一行包含一个整数t(1≤t≤10^4)——测试用例的数量。每个测试用例描述如下:

第一行包含两个整数n和k(1≤k<n≤2‧10^5)——药剂类型的总数和Nastya已经拥有的药剂类型的数量。

第二行包含n个整数c1、c2、…、cn(1≤ci≤10^9)——购买药剂的成本。

第三行包含k个不同的整数p1,p2,…,pk(1≤pi≤n)——药剂的指数Nastya已经有了无限的供应。

接下来是描述通过混合获得药剂的方法的n行。每行以整数mi(0≤mi<n)开始——混合类型 i(1≤i≤n)的药剂所需的药剂数量。然后这行包含mi不同的整数e1、e2、…、emi(1≤ej≤n ,ej≠i)——混合Ⅱ型药剂所需的药剂指数。如果此列表为空,则只能购买类型为 i 的药剂。保证不会通过一个或多个混合过程从自身获得任何药剂。保证所有测试用例的所有nn值之和不超过2∙10^5。同样,保证所有测试用例中所有mi值的总和不超过2∙10^5。

输出:

对于每个测试用例,输出n个整数——Nastya获得每种类型的药剂所需花费的最小硬币数。
输入样例:

4

5 1

30 8 3 5 10

3

3 2 4 5

0

0

2 3 5

0

3 2

5 143 3

1 3

1 2

0

2 1 2

5 1

5 4 1 3 4

2

2 4 5

3 3 5 4

2 1 4

1 5

0

4 2

1 1 5 4

2 4

3 2 4 3

0

2 2 4

1 2

输出样例

23 8 0 5 10 
0 143 0 
5 0 1 3 4 
0 0 0 0 

输入样例:

3

6 3

5 5 4 5 2 2

3 4 5

2 2 5

1 5

3 4 1 6

4 2 6 1 5

0

0

6 2

1 4 4 1 5 2

3 6

4 6 3 4 5

4 6 5 3 4

0

1 5

1 6

0

2 1

4 3

1

0

1 1

输出样例:

0 0 0 0 0 2 
0 0 0 0 0 0 
0 0 

 

#include<iostream>
#include<algorithm>
#include<vector>
#include<cstring>
using namespace std;
const int N=2e5+10;
long long dp[N];
long long c[N];
vector<int>v[N];
int dfs(int x)
{
	if(dp[x]!=-1) return dp[x];
	if(v[x].size()==0)
	{
		dp[x]=c[x];
		return dp[x];
	}
	long long sum=0;
	for(int i=0;i<v[x].size();i++)
	{
		sum+=dfs(v[x][i]);
	}
	dp[x]=min(sum,c[x]);
	return dp[x];
}
int main()
{
	int t;cin>>t;
	while(t--)
	{
		int n,k;cin>>n>>k;
		memset(dp,-1,sizeof dp);
		for(int i=1;i<=n;i++)
		{
			cin>>c[i];
			v[i].clear();
		}
		for(int i=1;i<=k;i++)
		{
			int x;cin>>x;
			c[x]=0;
	   }
	   for(int i=1;i<=n;i++)
	   {
	   	    int num;cin>>num;
	   	    for(int j=1;j<=num;j++)
	   	    {
	   	    	int x;cin>>x;
	   	    	v[i].push_back(x);
			   }
	   }
	   for(int i=1;i<=n;i++) cout<<dfs(i)<<" ";
	   cout<<endl;
	}
	return 0;
}

 

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值