「AOJ再挑戦106~110」の編集履歴(バックアップ)一覧はこちら

AOJ再挑戦106~110」(2014/02/07 (金) 16:57:00) の最新版変更点

追加された行は緑色になります。

削除された行は赤色になります。

*問106 Discounts of Buckwheat http://judge.u-aizu.ac.jp/onlinejudge/description.jsp?id=0106 そばを安く買う問題。 解法 200グラム 380円 1000グラム1520円 300グラム 550円 1200グラム 1870円 500グラム 850円 1500グラム 2244円 の商品があるのだと考えて動的計画法を適用すればきれいに解けます。 #include<stdio.h> int main(){ int gs[6]={2,10,3,12,5,15}; int vs[6]={380,1520,550,1870,850,2244}; int dp[51]={0}; for(int i=0;i<6;i++){ int g=gs[i]; int v=vs[i]; for(int j=0;j+g<=50;j++){ if(j>0&&dp[j]==0)continue; if(dp[j+g]==0||dp[j+g]>=dp[j]+v){ dp[j+g]=dp[j]+v; } } } int g; while(scanf("%d",&g)!=EOF){ if(g==0)break; printf("%d\n",dp[g/100]); } } *問107 Carry a Cheese http://judge.u-aizu.ac.jp/onlinejudge/description.jsp?id=0107 直方体のチーズが円形の穴を通るか判定する問題 解法 直方体の四角形の一番短い対角線が円の直径よりも小さいならチーズは穴を通ります。 これをきちんと証明するのは少し難しいですが直感的には明らかだと思います。 #include<stdio.h> #include<algorithm> int main(){ int a,b,c,n,t,r; while(1){ scanf("%d %d %d",&a,&b,&c); if((a|b|c)==0)break; t=std::max(a,std::max(b,c)); t=a*a+b*b+c*c-t*t; scanf("%d",&n); while(n--){ scanf("%d",&r); printf("%s\n",t<4*r*r?"OK":"NA"); } } } *問108 Operation of Frequency of Appearance http://judge.u-aizu.ac.jp/onlinejudge/description.jsp?id=0108 出現頻度操作の問題。 解法 そのまま実装。 再帰万歳(太陽万歳)。 最初の数字を除けば12以下の数しかならばいないんだからこのへんstd::mapを使わない理由はあるのだけれど。 それに対応するとコードが膨らむので対処はしない。 #include<stdio.h> #include<map> #include<string.h> int calcNext(int nums[12],int n,int deep,int reNums[12]){ std::map<int,int> memo; for(int i=0;i<n;i++){ int num=nums[i]; if(memo.find(num)==memo.end())memo[num]=0; memo[num]++; } int next[12]; for(int i=0;i<n;i++)next[i]=memo[nums[i]]; bool isLast=true; for(int i=0;i<n;i++){ if(next[i]!=nums[i])isLast=false; } if(isLast==true){ memcpy(reNums,next,sizeof(next)); return deep; }else{ return calcNext(next,n,deep+1,reNums); } } int main(){ int n,nums[12],ans[12]; while(1){ scanf("%d",&n); if(n==0)break; for(int i=0;i<n;i++)scanf("%d",&nums[i]); printf("%d\n",calcNext(nums,n,0,ans)); for(int i=0;i<n;i++){ if(i>0)printf(" "); printf("%d",ans[i]); } printf("\n"); } } *問109 Smart Calculator http://judge.u-aizu.ac.jp/onlinejudge/description.jsp?id=0109 与えられた四則演算の式を計算する問題。 解法 再帰下降構文解析、私にとって書きやすい方法で書いてみたので参考にしてはいけない。 http://d.hatena.ne.jp/nanikaka/20110829/1314603165 この人みたいに関数の粒度を細かくするのが正しいらしい。 #include<stdio.h> #include<ctype.h> int ope(int& p,char *siki,int pri,int deep){ bool first=true; int num=0; char c=siki[p]; while(c!='='&&c!='\0'){ c=siki[p]; if(c=='('){ p++; num=ope(p,siki,0,deep+1); p++; } if(c==')'){ return num; } if(c=='-'&&first==true){ num=0; while(isdigit(siki[p+1])){ num=num*10+siki[p+1]-'0'; p++; } num=-num; p++; } if(c=='+'){ if(1<=pri){ return num; }else{ p++; num+=ope(p,siki,1,deep+1); } } if(c=='-'&&first==false){ if(1<=pri){ return num; }else{ p++; num-=ope(p,siki,1,deep+1); } } if(c=='*'){ if(2<=pri){ return num; }else{ p++; num*=ope(p,siki,2,deep+1); } } if(c=='/'){ if(2<=pri){ return num; }else{ p++; num/=ope(p,siki,2,deep+1); } } if(isdigit(c)){ num=c-'0'; while(isdigit(siki[p+1])){ num=num*10+siki[p+1]-'0'; p++; } p++; } first=false; } return num; } int main(){ int n; char siki[101]; scanf("%d",&n); while(n--){ scanf("%s",siki); int p=0; printf("%d\n",ope(p,siki,0,0)); } }
*問106 Discounts of Buckwheat http://judge.u-aizu.ac.jp/onlinejudge/description.jsp?id=0106 そばを安く買う問題。 解法 200グラム 380円 1000グラム1520円 300グラム 550円 1200グラム 1870円 500グラム 850円 1500グラム 2244円 の商品があるのだと考えて動的計画法を適用すればきれいに解けます。 #include<stdio.h> int main(){ int gs[6]={2,10,3,12,5,15}; int vs[6]={380,1520,550,1870,850,2244}; int dp[51]={0}; for(int i=0;i<6;i++){ int g=gs[i]; int v=vs[i]; for(int j=0;j+g<=50;j++){ if(j>0&&dp[j]==0)continue; if(dp[j+g]==0||dp[j+g]>=dp[j]+v){ dp[j+g]=dp[j]+v; } } } int g; while(scanf("%d",&g)!=EOF){ if(g==0)break; printf("%d\n",dp[g/100]); } } *問107 Carry a Cheese http://judge.u-aizu.ac.jp/onlinejudge/description.jsp?id=0107 直方体のチーズが円形の穴を通るか判定する問題 解法 直方体の四角形の一番短い対角線が円の直径よりも小さいならチーズは穴を通ります。 これをきちんと証明するのは少し難しいですが直感的には明らかだと思います。 #include<stdio.h> #include<algorithm> int main(){ int a,b,c,n,t,r; while(1){ scanf("%d %d %d",&a,&b,&c); if((a|b|c)==0)break; t=std::max(a,std::max(b,c)); t=a*a+b*b+c*c-t*t; scanf("%d",&n); while(n--){ scanf("%d",&r); printf("%s\n",t<4*r*r?"OK":"NA"); } } } *問108 Operation of Frequency of Appearance http://judge.u-aizu.ac.jp/onlinejudge/description.jsp?id=0108 出現頻度操作の問題。 解法 そのまま実装。 再帰万歳(太陽万歳)。 最初の数字を除けば12以下の数しかならばいないんだからこのへんstd::mapを使わない理由はあるのだけれど。 それに対応するとコードが膨らむので対処はしない。 #include<stdio.h> #include<map> #include<string.h> int calcNext(int nums[12],int n,int deep,int reNums[12]){ std::map<int,int> memo; for(int i=0;i<n;i++){ int num=nums[i]; if(memo.find(num)==memo.end())memo[num]=0; memo[num]++; } int next[12]; for(int i=0;i<n;i++)next[i]=memo[nums[i]]; bool isLast=true; for(int i=0;i<n;i++){ if(next[i]!=nums[i])isLast=false; } if(isLast==true){ memcpy(reNums,next,sizeof(next)); return deep; }else{ return calcNext(next,n,deep+1,reNums); } } int main(){ int n,nums[12],ans[12]; while(1){ scanf("%d",&n); if(n==0)break; for(int i=0;i<n;i++)scanf("%d",&nums[i]); printf("%d\n",calcNext(nums,n,0,ans)); for(int i=0;i<n;i++){ if(i>0)printf(" "); printf("%d",ans[i]); } printf("\n"); } } *問109 Smart Calculator http://judge.u-aizu.ac.jp/onlinejudge/description.jsp?id=0109 与えられた四則演算の式を計算する問題。 解法 再帰下降構文解析、私にとって書きやすい方法で書いてみたので参考にしてはいけない。 http://d.hatena.ne.jp/nanikaka/20110829/1314603165 この人みたいに関数の粒度を細かくするのが正しいらしい。 #include<stdio.h> #include<ctype.h> int ope(int& p,char *siki,int pri,int deep){ bool first=true; int num=0; char c=siki[p]; while(c!='='&&c!='\0'){ c=siki[p]; if(c=='('){ p++; num=ope(p,siki,0,deep+1); p++; } if(c==')'){ return num; } if(c=='-'&&first==true){ num=0; while(isdigit(siki[p+1])){ num=num*10+siki[p+1]-'0'; p++; } num=-num; p++; } if(c=='+'){ if(1<=pri){ return num; }else{ p++; num+=ope(p,siki,1,deep+1); } } if(c=='-'&&first==false){ if(1<=pri){ return num; }else{ p++; num-=ope(p,siki,1,deep+1); } } if(c=='*'){ if(2<=pri){ return num; }else{ p++; num*=ope(p,siki,2,deep+1); } } if(c=='/'){ if(2<=pri){ return num; }else{ p++; num/=ope(p,siki,2,deep+1); } } if(isdigit(c)){ num=c-'0'; while(isdigit(siki[p+1])){ num=num*10+siki[p+1]-'0'; p++; } p++; } first=false; } return num; } int main(){ int n; char siki[101]; scanf("%d",&n); while(n--){ scanf("%s",siki); int p=0; printf("%d\n",ope(p,siki,0,0)); } } *問110 Alphametic http://judge.u-aizu.ac.jp/onlinejudge/description.jsp?id=0110 簡単な覆面残を試す問題 解法 数字を文字列としてみてXを一つずつ数字を代入して 小学生の足し算の要領で足していって試すだけです。 #include<stdio.h> #include<string.h> #include<algorithm> bool isAddOK(char* L1,char* M1,char* R1){ int pL=strlen(L1)-1; int pM=strlen(M1)-1; int pR=0; char add=0,numL,numM,T; char tempR[255]; while(add!=0||0<=pL||0<=pM){ numL=pL<0?0:L1[pL]-'0'; numM=pM<0?0:M1[pM]-'0'; T=numL+numM+add; tempR[pR]=T%10+'0'; add=T/10; pR++; pL--; pM--; } tempR[pR]='\0'; std::reverse(tempR,tempR+pR); return strcmp(R1,tempR)==0; } void changeX(char* nums,char* reNums,char c){ for(int i=0;i<=strlen(nums);i++){ if(nums[i]=='X')reNums[i]=c; else reNums[i]=nums[i]; } } int main(){ char L[255],M[255],R[255],L1[255],M1[255],R1[255]; while(scanf("%[^+]%*c%[^=]%*c%[^\n]%*c",L,M,R)!=EOF){ bool hit=false; for(char i='0';i<='9';i++){ if(i=='0' && L[0]=='0' && strlen(L)>1)continue; if(i=='0' && M[0]=='0' && strlen(M)>1)continue; if(i=='0' && R[0]=='0' && strlen(R)>1)continue; changeX(L,L1,i); changeX(M,M1,i); changeX(R,R1,i); if(isAddOK(L1,M1,R1)){ printf("%c\n",i); hit=true; } } if(hit==false)printf("NA\n"); } }

表示オプション

横に並べて表示:
変化行の前後のみ表示: