救命(洛谷 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;
}
View Code
原文地址:https://www.cnblogs.com/harden/p/5840231.html