0201 Wrought Gold Master
解法
アイテムを一つずつ確かめて、錬金で安く作れるならその値段に改定します。
改定した値段で更に調べなおして、値段が改定できなくなるまでループし続ければ答えがもとまります。
この方法でも十分速度はでますが、すべてのアイテムの最低値を求めており無駄があります。
もっと賢い方法として両手法という方法があるようです。
#include<iostream>
#include<map>
#include<string>
#include<vector>
using namespace std;
void setData(int n){
map<string,int> items;
map<string,vector<string> > process;
map<string,int>::iterator itemIt;
vector<string>::iterator processIt,end;
int Count=1,value,m,k,sum;
string name,item;
for(int i=0;i<n;i++){
std::cin>>name>>value;
items[name]=value;
}
std::cin>>m;
for(int i=0;i<m;i++){
std::cin>>name>>k;
for(int i=0;i<k;i++){
cin>>item;
process[name].push_back(item);
}
}
cin>>name;
while(Count>0){
Count=0;
itemIt=items.begin();
while(itemIt!=items.end()){
sum=0;
if(process.find((*itemIt).first)!=process.end()){
processIt=process[(*itemIt).first].begin();
end=process[(*itemIt).first].end();
while(processIt!=end){
sum+=items[*processIt];
processIt++;
}
if(sum<(*itemIt).second){
items[(*itemIt).first]=sum;
Count++;
}
}
itemIt++;
}
}
cout<<items[name]<<"\n";
}
int main(){
int n;
while(scanf("%d",&n),n>0){
setData(n);
}
}
0202 At Boss's Expense
飲食店で食べ物の値段と予算が与えられます。
食べ物を組み合わせて、予算額以下で素数になっている注文額を求めよという問題。
1円は特例的に素数に含むようです。
解法
下から足しこんでいくだけです。
値段1円のものがあったら計算量が増えるのでその時は全ての値段を作ることができることを逆利用して上から見ていきます。
普通の値段なら下から足しこんでいくだけです。
重複して足しこんでいる部分があるので重複を削除できればもう少し高速化できるかもしれません。
#include<stdio.h>
#include<string.h>
#include <algorithm>
int so[1000002];
void setSo(){
for(int i=2;i<1000001;i++)
so[i]=i%2;
int k;
for(int i=3;i<=1000;i+=2){
if(so[i]==true){
k=i*2;
for(int j=i*3;j<1000001;j+=(k)){
so[j]=false;
}
}
}
so[0]=false;
so[1]=true;
so[2]=true;
}
bool permMemo[1000002];
void calc(int n,int x){
int foods[31],ans=-1,t;
bool isOne=false;
for(int i=0;i<n;i++){
scanf("%d",&foods[i]);
if(foods[i]==1) isOne=true;
}
if(isOne==true){
//1があったので最大の素数を求める
for(int i=x;i>0;i--){
if(so[i]==true){
ans=i;
break;
}
}
}else{
memset(permMemo,false,x+1);
permMemo[0]=true;
std::sort(foods,foods+n);
for(int i=0;i<x;i++){
//0から値段を一つずつ足しこんでいく
if(permMemo[i]==true){
for(int j=0;j<n;j++){
t=i+foods[j];
if(x<t)break;
permMemo[t]=true;
if(so[t]==true){
ans=t>ans?t:ans;
}
}
}
}
}
if(ans==-1){
printf("NA\n");
}else{
printf("%d\n",ans);
}
}
int main(){
int n,x;
setSo();
while(scanf("%d %d",&n,&x),n+x>0){
calc(n,x);
}
}
0203 A New Plan of Aizu Ski Resort
#include<stdio.h>
#include<string.h>
int map[16][18];
int roots[18][18];
void setMap(int x,int y){
memset(map,0,16*18*4);
for(int i=0;i<y;i++){
for(int j=1;j<=x;j++){
scanf("%d",&map[i][j]);
}
}
memset(roots,0,18*18*4);
for(int i=1;i<=x;i++){
if(map[0][i]==0){
roots[0][i]=1;
}
}
int t,r;
for(int i=0;i<y-1;i++){
for(int j=1;j<=x;j++){
t=map[i][j];
r=roots[i][j];
if(t==1){
//障害物なので何もしない
roots[i][j]=0;
continue;
}else if(t==2 && map[i+2][j]!=1){
//ジャンプ台かつジャンプ先が障害物でないなら
roots[i+2][j]+=r;
}else if(t==0){
//斜面なら
if(map[i+1][j-1]==0) roots[i+1][j-1]+=r;
if(map[i+1][j+0]!=1) roots[i+1][j+0]+=r;
if(map[i+1][j+1]==0) roots[i+1][j+1]+=r;
}
}
}
int sum=0;
for(int i=1;i<=x;i++) sum+=roots[y][i]+roots[y-1][i];
printf("%d\n",sum);
}
int main(){
int x,y;
while(scanf("%d %d",&x,&y),x+y>0){
setMap(x,y);
}
}
0204 UFO Shooting Down Operation
解法
この問題は当たり判定の数学的記述ができるかどうだけです。
三角関数と正射影の概念を使ってcalc関数で当たり判定を簡潔に記述します。
後は移動処理、ビームの半径内に入った機体の削除処理、ビームの当たり処理、削除処理を記述します。
、
#include<stdio.h>
#include<math.h>
#include<vector>
#include <algorithm>
struct enemy{
double x,y,len,moveX,moveY,r,v;
void setData(double sx,double sy,double size,double sv){
len=sqrt(sx*sx+sy*sy);
moveX=-sv*sx/len;
moveY=-sv*sy/len;
x=sx;
y=sy;
r=size;
v=sv;
}
void move(){
x+=moveX;
y+=moveY;
len-=v;
}
bool operator<(const enemy e)const{
return len<e.len;
}
};
bool calc(double bx,double by,double rb,double ex,double ey,double re){
double len1=sqrt(bx*bx+by*by);
double lenSin=fabs(bx*ey-ex*by)/len1;
if(re<lenSin) return false;
double lenCos=(bx*ex+by*ey)/len1;
double len2=sqrt(re*re-lenSin*lenSin);
double ans=lenCos+len2;
if(ans<=rb)return false;
return true;
}
void setData(double R,int N){
std::vector<enemy> enemys;
std::vector<enemy>::iterator it;
enemy e;
double x0,y0,r,v;
for(int i=0;i<N;i++){
scanf("%lf %lf %lf %lf",&x0,&y0,&r,&v);
e.setData(x0,y0,r,v);
enemys.push_back(e);
}
int inCount=0;
double bx,by;
while(enemys.empty()==false){
it=enemys.begin();
while(it!=enemys.end()){
//移動処理
(*it).move();
//レーザーの有効圏内を割ったので削除処理
if((*it).len<=R){
it=enemys.erase(it);
inCount++;
}else{
it++;
}
}
if(enemys.empty()) break;
//一番近いUFOに並べ替える
std::sort(enemys.begin(),enemys.end());
it=enemys.begin();
bx=(*it).x;
by=(*it).y;
while(it!=enemys.end()){
//ビームの射線上に他に当たり判定がないか確かめて敵を削除する。
if(calc(bx,by,R,(*it).x,(*it).y,(*it).r)){
it=enemys.erase(it);
}else{
it++;
}
}
}
printf("%d\n",inCount);
}
int main(){
double R;
int N;
while(1){
scanf("%lf %d",&R,&N);
if(R==0 && N==0) break;
setData(R,N);
}
}
0205 Rock, Paper, Scissors
解法
グーを1チョキを2パーを4としてビット演算に符号化して解いてみました。
この方法なら何人に増えても変数を変えるだけで対応できます。
#include<stdio.h>
int main(){
int te[5],kekka[4];
int all;
while(scanf("%d",&te[0]),te[0]!=0){
all=(1<<(te[0]-1));
for(int i=1;i<5;i++){
scanf("%d",&te[i]);
all|=(1<<(te[i]-1));
}
if(all==7 || all==4 || all==2 || all==1){
kekka[1]=kekka[2]=kekka[3]=3;
}else if(all==3){
//グーとチョキ
kekka[1]=1;
kekka[2]=2;
}else if(all==5){
//グーとパー
kekka[1]=2;
kekka[3]=1;
}else if(all==6){
//チョキとパー
kekka[2]=1;
kekka[3]=2;
}
for(int i=0;i<5;i++)printf("%d\n",kekka[te[i]]);
}
}
0206 Next Trip
解法
単純に足し算するだけの問題です。
#include<stdio.h>
int main(){
int l,n,m,sum,ans;
while(scanf("%d",&l),l!=0){
ans=sum=0;
for(int i=0;i<12;i++){
scanf("%d %d",&m,&n);
sum+=m-n;
if(sum>=l && ans==0){
ans=i+1;
}
}
if(ans==0){
printf("NA\n");
}else{
printf("%d\n",ans);
}
}
}
0207 Block
解法
奇麗に整え直したコードを掲載しようと思ったのですが、簡単な問題なのに奇麗に直したコードがなぜか通らず。
最初に書いたあまり良くないコードを掲載しておきます。
盤面を生成して再帰で探索しています。
#include <stdio.h>
void addBlock(int color,int d,int x,int y);
void setMap();
void search(int x,int y);
int map[102][102];
int xs,ys,xg,yg;
int w,h;
bool endFlag;
int startColor;
int main(){
scanf("%d %d",&w,&h);
while(w!=0 || h!=0){
setMap();
scanf("%d %d",&w,&h);
}
}
void setMap(){
for(int i=1;i<=h;i++){
for(int j=1;j<=w;j++){
map[i][j]=-1;
}
}
endFlag=false;
scanf("%d %d",&xs,&ys);
scanf("%d %d",&xg,&yg);
int n;
scanf("%d",&n);
int c,d,x,y;
for(int i=0;i<n;i++){
scanf("%d %d %d %d",&c,&d,&x,&y);
addBlock(c,d,x,y);
}
startColor=map[xs][ys];
if(startColor!=-1){
search(xs,ys);
}
if(endFlag==true)
{
printf("OK\n");
}else{
printf("NG\n");
}
}
void search(int x,int y){
if(w>=x && x>0 && h>=y && y>0){
if(map[x][y]!=-1 && map[x][y]==startColor){
if(y==yg && x==xg){
endFlag=true;
return ;
}
map[x][y]=-1;
search(x+1,y);
if(endFlag==true) return ;
search(x-1,y);
if(endFlag==true) return ;
search(x,y+1);
if(endFlag==true) return ;
search(x,y-1);
if(endFlag==true) return ;
}
}
}
void addBlock(int color,int d,int x,int y)
{
if(d==0){
//横向き
map[x][y]=map[x+1][y]=map[x+2][y]=map[x+3][y]=color;
map[x][y+1]=map[x+1][y+1]=map[x+2][y+1]=map[x+3][y+1]=color;
}else{
//縦向き
map[x][y]=map[x][y+1]=map[x][y+2]=map[x][y+3]=color;
map[x+1][y]=map[x+1][y+1]=map[x+1][y+2]=map[x+1][y+3]=color;
}
}
0208 Room Numbers of a Hospital
解法
私の考えたコードを掲載しようかと考えたのですがネットにとても美しい解法があったのでそちらを掲載することにしました。
簡単な問題を解くだけですが、シンプルで無駄がないいいコードです。
#include<stdio.h>
//http://program.pinemz.net/article/168162542.htmlを参考にしました
int t[]={0,1,2,3,5,7,8,9};
void saiki(int n){
if(n>=8){
saiki(n/8);
}
printf("%d",t[n%8]);
}
int main(){
int n;
while(scanf("%d",&n),n>0){
saiki(n);
printf("\n");
}
}
0209 Scene in a Picture
解法
普通に左上から画像を照合するだけです。
#include<stdio.h>
void roundPict(int rPict[4][51][51],int r,int m){
for(int y=0;y<m;y++){
for(int x=0;x<m;x++){
rPict[r][x][m-y-1]=rPict[r-1][y][x];
}
}
}
void getPictTop(int rPict[4][51][51],int m,int xTops[4],int yTops[4]){
for(int r=0;r<4;r++){
bool hit=false;
for(int y=0;y<m;y++){
for(int x=0;x<m;x++){
if(rPict[r][y][x]!=-1){
xTops[r]=x;
yTops[r]=y;
hit=true;
break;
}
}
if(hit==true)break;
}
}
}
bool setData(){
int rPict[4][51][51],map[101][101],n,m;
int xTops[4],yTops[4];
scanf("%d %d",&n,&m);
if(n==0 && m==0) return false;
for(int i=0;i<n;i++){
for(int j=0;j<n;j++){
scanf("%d",&map[i][j]);
}
}
for(int i=0;i<m;i++){
for(int j=0;j<m;j++){
scanf("%d",&rPict[0][i][j]);
}
}
roundPict(rPict,1,m);
roundPict(rPict,2,m);
roundPict(rPict,3,m);
getPictTop(rPict,m,xTops,yTops);
int side=n-m+1;
bool hit;
int ansX=101,ansY=101,tx,ty;
for(int y=0;y<side;y++){
if(ansY<y) break;
for(int x=0;x<side;x++){
for(int r=0;r<4;r++){
hit=true;
for(int dy=0;dy<m;dy++){
for(int dx=0;dx<m;dx++){
if(rPict[r][dy][dx]!=-1 && rPict[r][dy][dx]!=map[y+dy][x+dx]){
hit=false;
break;
}
}
if(hit==false) break;
}
if(hit==true){
tx=x+xTops[r];
ty=y+yTops[r];
if(ansY>ty || (ansY==ty && ansX>tx)){
ansY=ty;
ansX=tx;
}
}
}
}
}
if(ansY==101){
printf("NA\n");
}else{
printf("%d %d\n",ansX+1,ansY+1);
}
return true;
}
int main(){
while(setData()){
}
}
最終更新:2011年09月27日 14:54