救命(洛谷 U4525)
题目背景
XS中学的校长积劳成疾,最终由于无聊而卧病在沙发。需要药(pi)水(gu)拯救他的生活。
题目描述
现在有n种药水,编号分别为1..n,能拯救校长的药水编号为n
每个药水都可以购买到,但有的价格很便宜,有的很贵。
你还知道m种神奇的合成方法,可以将某些不同的药水合成成为一个新的药水。
现在,你需要求出合成出n号药水所需要花费的最小金钱,以及在保证花费最小情况下的最少需要合成的次数。
输入输出格式
输入格式:
第一行两个数n,m
接下来n行,每行有一个数a[i],表示i号药水的价格。
接下来m行,每行描述一个合成方法。
对于每个合成方法:第一个数x表示所需要的药水的个数。接下来x个数,分别表示所需要的每个药水的编号,最后一个数表示这x个药水所合成的药水的编号
输出格式:
仅两个数,分别表示最小花费和满足该花费的最小合成次数,中间用空格隔开。
输入输出样例
输入样例#1:
10 4 1 2 3 100 4 2 2 2 100 100 3 1 2 3 4 2 4 5 10 2 6 7 9 2 9 8 4
输出样例#1:
10 2
说明
n<=1000
m<=10000
2<=x<=10
Tips:看标签!!!
/* 对于每种药,统计一个mon代表最小花费,step代表在mon基础上的最小步数, 不断用能合成i这种药的Σmon[j] 来更新mon[i],共更新n次就可以,最后求 mon[n]。 */ #include<cstdio> #include<iostream> #define N 1010 #define M 10010 using namespace std; int mon[N],step[N],n,m; struct node { int tot,s[11],t; };node a[M]; int read() { char c=getchar();int num=0,flag=1; while(c<'0'||c>'9'){if(c=='-')flag=-1;c=getchar();} while(c>='0'&&c<='9'){num=num*10+c-'0';c=getchar();} return num*flag; } int main() { n=read();m=read(); for(int i=1;i<=n;i++) mon[i]=read(); for(int i=1;i<=m;i++) { a[i].tot=read(); for(int j=1;j<=a[i].tot;j++) a[i].s[j]=read(); a[i].t=read(); } for(int t=1;t<=n;t++) { int flag=0; for(int i=1;i<=m;i++) { int sum=0,maxn=0; for(int j=1;j<=a[i].tot;j++) sum+=mon[a[i].s[j]],maxn+=step[a[i].s[j]]; if(sum<mon[a[i].t]) { step[a[i].t]=maxn+1; mon[a[i].t]=sum; flag=1; } if(sum==mon[a[i].t]&&maxn+1<step[a[i].t]) step[a[i].t]==maxn+1,flag=1; } if(!flag)break; } printf("%d %d",mon[n],step[n]); return 0; }