#include<stdio.h> #include<iostream> #include<string.h> #include<ctype.h> #include<math.h> #include<map> #include<set> #include<vector> #include<queue> #include<string> #include<algorithm> #include<time.h> #include<bitset> using namespace std; void fre(){freopen("c://test//input.in","r",stdin);freopen("c://test//output.out","w",stdout);} #define MS(x,y) memset(x,y,sizeof(x)) #define MC(x,y) memcpy(x,y,sizeof(x)) #define MP(x,y) make_pair(x,y) #define ls o<<1 #define rs o<<1|1 typedef long long LL; typedef unsigned long long UL; typedef unsigned int UI; template <class T> inline void gmax(T &a,T b){if(b>a)a=b;} template <class T> inline void gmin(T &a,T b){if(b<a)a=b;} const int N=0,M=0,Z=1e9+7,maxint=2147483647,ms31=522133279,ms63=1061109567,ms127=2139062143;const double eps=1e-8,PI=acos(-1.0);//.0 double mm1,mm2,cc1; int n,m1,m2; char s[10][24]; int c1,c2,siz; int f[1005][605]; int C1[10],C2[10]; int num[10]; void dfs(int y,int x) { if(y==0&&x==0)return; int o=f[y][x]; ++num[o]; dfs(y-C1[o],x-C2[o]); } int main() { while(~scanf("%lf%lf%d",&mm1,&mm2,&n)) { MS(num,0); m1=mm1*100+0.1; m2=mm2*30; MS(f,0);f[0][0]=1; for(int i=1;i<=n;i++) { scanf("%s",s[i]); scanf("%d",&c2); scanf("%*d");getchar();scanf("%d",&siz); if(siz==1)c2*=30; else if(siz==2)c2*=15; else c2*=10; scanf("%lf",&cc1);c1=cc1*100+0.1; C1[i]=c1; C2[i]=c2; if(c1==0&&c2==0)continue;//特判没有意义的情况 for(int j=c1;j<=m1;j++) { for(int k=c2;k<=m2;k++)if(f[j][k]==0&&f[j-c1][k-c2]) { f[j][k]=i; } } } if(f[m1][m2]==0)puts("IMPOSSIBLE"); else { dfs(m1,m2); for(int i=1;i<=n;i++)if(num[i])printf("%s %d\n",s[i],num[i]); } } return 0; } /* 【trick&&吐槽】 1,不要太畏惧double 有些情况下我们是通过完全与int相同的做法做 有些情况下我们是可以把double转化为int的 2,DP常常要考虑到拓扑序和环。 对于这题,如果有初始m1=m2=0,那么答案一定是yes 而如果对于一瓶酒,有c1=c2=0,那么这瓶酒我们不需要考虑啦(本题没有这个数据233) 3,编译器问题导致了,如果一个小数乘一个倍数,很有可能是0.99999999这样的数然后被认定为0。 所以像是+0.1这样维护精度的细节一定要注意 【题意】 去喝酒!!! 我们初始有m1(double,[0,10],小数点后最多两位)的钱,想把这钱恰好花光。 而且想喝到的酒精量恰为m2(double,[0,20],小数点后最多两位)。 有n种酒,数量都无限,对于每种酒,含有以下属性: 1,名称。(长度不超过20的字符串) 2,一整瓶的酒精含量。([0,100]范围内的int) 3,所对应的价格。(double,小数点后最多只有2位) 问你是否能够达到这个"双恰好的要求" 【类型】 DP 【分析】 首先,这道题的类型看起来像是一个DP。 但是,因为这题给出的下标可能为double! 不过,因为小数点后最多只有2位,我们可以乘上一个倍数,将其转换为整数。 对于钱数,*100即可 对于酒精量,我们首先是有必要*10的,同时我们还要解决1/2,1/3的情况。 于是我们可以对目标酒精量*60,对每瓶的酒精量分别*60,*30,*20, 或者我们可以对目标酒精量*30,对每瓶的酒精量分别*30,*15,*10,(后者可以使得效率提高一倍) 然后做个DP就可以啦。记录前驱的酒,用dfs输出一下方案即可。 【时间复杂度&&优化】 O(nm) 【数据】 input 10.00 9.0 2 fire 2 1/1 4.00 water 10 1/2 2.00 output fire 2 water 1 input 2.00 3.0 3 firewater 1 1/1 1.00 windwater 1 1/1 1.00 earthwater 1 1/1 1.00 output IMPOSSIBLE */