题意:中文题
思路:完全背包,以血量作为背包容量,以花费晶石做为价值,求花费晶石最小也就是求背包价值最小,注意,dp[i]表示的是血量为i的怪物恰好被杀死的最小花费,所以如果出现i更大,但是花费更小的,应该要更新答案,从后面遍历每次判断dp[i-1]和dp[i]的大小就可以了,题目中还有一个条件,防御值,当防御值大于攻击力的时候攻击无效,所以开一个二维即可,每次判断一下技能能否奏效,如果不能则不进入背包,最后dp式为 dp[t][j]=max(dp[t][j],dp[t][j-pi]+ki)
AC代码:怕查重 ,还是删了。。。
代码:
#include "iostream" #include "string.h" #include "stack" #include "queue" #include "string" #include "vector" #include "set" #include "map" #include "algorithm" #include "stdio.h" #include "math.h" #pragma comment(linker, "/STACK:102400000,102400000") #define ll long long #define endl (" ") #define bug(x) cout<<x<<" "<<"UUUUU"<<endl; #define mem(a,x) memset(a,x,sizeof(a)) #define mp(x,y) make_pair(x,y) #define pb(x) push_back(x) #define ft (frist) #define sd (second) #define lrt (rt<<1) #define rrt (rt<<1|1) using namespace std; const long long INF = 1e18+1LL; const int inf = 1e9+1e8; const int N=1e5+100; const ll mod=1e9+7; ll dp[15][2500],n,m,a[N],b[N],ct[1005],vi[1005]; int main(){ while(~scanf("%I64d %I64d",&n, &m)){ for(int i=1; i<=n; ++i){ scanf("%I64d %I64d",&a[i], &b[i]); } for(int i=1; i<=m; ++i){ scanf("%I64d %I64d",&ct[i], &vi[i]); } for(int i=0; i<=10; ++i){ for(int j=0; j<=2000; ++j){ if(j==0) dp[i][j]=0; else dp[i][j]=inf; } } for(int t=0; t<=10; ++t){ for(int i=1; i<=m; ++i){ if(vi[i] < t) continue; for(int j=0; j<=2000; ++j){ //if(j-vi[i]+t >= 0) dp[t][j]=min(dp[t][j], dp[t][j-vi[i]+t]+ct[i]); //else //dp[t][j]=min(dp[t][j], ct[i] ); } } } ll ans=0; for(int i=0; i<=10; ++i){ for(int j=2000; j>=1; --j){ if(dp[i][j]<=dp[i][j-1]){ dp[i][j-1]=dp[i][j]; } } } int flag=0; for(int i=1; i<=n; ++i){ if(dp[b[i]][a[i]] >= inf) flag=1; else ans+=dp[b[i]][a[i]]; } if(flag) printf("-1 "); else printf("%I64d ",ans); } return 0; }