裏 RjpWiki

Julia ときどき R, Python によるコンピュータプログラム,コンピュータ・サイエンス,統計学

2007 円ぶんの切手を買う方法

2014年11月26日 | ブログラミング

1 円,2 円,10 円,52 円,82 円,280 円の切手を合計が 2007 円になるように買う方法を求めよ。ただし,買う枚数を最小にせよ。

素直に考えて,280 円切手を 7 枚,10 円切手を 4 枚,2 円切手を 3 枚,1 円切手を 1 枚,つまり,280*7 + 10*4 + 2*3 + 1*1 =2007 ということで,15 枚が取りあえずの候補。

280 円切手だけは 2007 %/% 280 = 7 枚までしか買えないがそのほかは,まあ他の制約はあるけど,15 枚以下でないと候補にはならない。そこで,効率なんかは考えずにプログラムをして,以下のプログラムを得る。

fee = 2007
for (i280 in 0:(fee %/% 280)) {
  for(i82 in 0:15) {
    for (i52 in 0:15) {
      for (i10 in 0:15) {
        for (i2 in 0:15) {
          i1 = fee-(i280*280+i82*82+i52*52+i10*10+i2*2)
          if (i1 < 0) break
          if (sum(c(i1, i2, i10, i52, i82, i280)) <= 15) {
            cat(i1, i2, i10, i52, i82, i280, "\n")
          }
        }
      }
    }
  }
}

どれくらい計算時間が掛かるか分からないが(いや,たいしたことないことは分かる),実行して見ると,以下の結果が表示される。

1 0 1 2 6 5
1 3 0 3 2 6
1 3 4 0 0 7

つまり
1 円切手 1 枚,2 円切手 0 枚,10 円切手 1 枚,52 円切手 2 枚,82 円切手 6 枚,280 円切手 5 枚。計 15 枚で 2007円。
1 円切手 1 枚,2 円切手 3 枚,10 円切手 0 枚,52 円切手 3 枚,82 円切手 2 枚,280 円切手 6 枚。計 15 枚で 2007円。
1 円切手 1 枚,2 円切手 3 枚,10 円切手 4 枚,52 円切手 0 枚,82 円切手 0 枚,280 円切手 7 枚。計 15 枚で 2007円。
のいずれでもよい。

コメント
  • X
  • Facebookでシェアする
  • はてなブックマークに追加する
  • LINEでシェアする

2 進表記と BCD 表記

2014年11月26日 | ブログラミング

2 桁の整数のうち,2 進数表記と BCD 表記に含まれる 1 の個数が同じになる整数はいくつあるか。

馬鹿馬鹿しい問題だけど...

# 2 進数表記に含まれる 1 の個数
bin = function(n) {
  count = 0
  repeat {
      count = count + n %% 2
      n = n %/% 2
      if (n == 0) return(count)
  }
}
# 0~9 の BCD 表記に含まれる 1 の個数
count1 = numeric(10)
for (d in 0:9) count1[d+1] = bin(d)
# 2 桁の整数の 2 進数表記と BCD 表記に含まれる 1 の個数が同じかどうか
same = logical(99)
for (n in 11:99) {
    same[n] = bin(n) == count1[n %/% 10+1] + count1[n %% 10+1]
}
sum(same) # 同じになる数の個数
(1:99)[same] # そのような数のリスト

実行結果

> sum(same) # 同じになる数の個数
[1] 20
> (1:99)[same] # そのような数のリスト
 [1] 12 13 18 19 24 25 26 27 38 39 48 49 52 53 70 71 78 79 98 99

コメント
  • X
  • Facebookでシェアする
  • はてなブックマークに追加する
  • LINEでシェアする

金額最安経路

2014年11月26日 | ブログラミング

エネルギー最短経路の問題と同じ。ただ,対称行列であるところが違うが。

効率がよいか悪いか分からない新しい言語(?)を覚えるまでもない。

route = matrix(c(
0, 200,  200, 390, 160, 220,
200, 0, 160, 220, 220, 310,
200, 160, 0, 310, 220, 310,
390, 220, 310, 0, 470, 550,
160, 220, 220, 470, 0, 220,
220, 310, 310, 550, 220, 0), ncol=6, byrow=TRUE)
station = c("東京", "新宿", "渋谷", "三鷹", "錦糸町", "北千住")
dimnames(route) = list(station, station)
# 料金表
route
       東京 新宿 渋谷 三鷹 錦糸町 北千住
東京      0  200  200  390    160    220
新宿    200    0  160  220    220    310
渋谷    200  160    0  310    220    310
三鷹    390  220  310    0    470    550
錦糸町  160  220  220  470      0    220
北千住  220  310  310  550    220      0

library(e1071)

# 東京から始まり東京で終わる場合
d = permutations(length(station))
d = d[d[,1] == 1,]
fee = apply(d, 1, function(from) sum(route[cbind(from, c(from[-1], from[1]))]))
p = which.min(fee)
fee[p]
apply(d[fee == fee[p],], 1, function(n) station[c(n, 1)])

# 東京から始まり錦糸町で終わる場合
d = permutations(length(station))
d = d[d[,1] == 1 & d[,6] == 5,]
fee = apply(d, 1, function(from) sum(route[cbind(from[-6], from[-1])]))
p = which.min(fee)
fee[p]
apply(d[fee == fee[p],], 1, function(n) station[n])

径路は列方向に見る

東京から始まり東京で終わる場合

> fee[p] # 料金
[1] 1390
> apply(d[fee == fee[p],], 1, function(n) station[c(n, 1)])
     [,1]     [,2]     [,3]     [,4]    
[1,] "東京"   "東京"   "東京"   "東京"  
[2,] "渋谷"   "新宿"   "北千住" "北千住"
[3,] "三鷹"   "三鷹"   "錦糸町" "錦糸町"
[4,] "新宿"   "渋谷"   "渋谷"   "新宿"  
[5,] "錦糸町" "錦糸町" "三鷹"   "三鷹"  
[6,] "北千住" "北千住" "新宿"   "渋谷"  
[7,] "東京"   "東京"   "東京"   "東京"  

東京から始まり錦糸町で終わる場合

> fee[p] # 料金
[1] 1260
> apply(d[fee == fee[p],], 1, function(n) station[n])
     [,1]     [,2]    
[1,] "東京"   "東京"  
[2,] "渋谷"   "新宿"  
[3,] "三鷹"   "三鷹"  
[4,] "新宿"   "渋谷"  
[5,] "北千住" "北千住"
[6,] "錦糸町" "錦糸町"

コメント
  • X
  • Facebookでシェアする
  • はてなブックマークに追加する
  • LINEでシェアする

2 進数で表したとき,ビットが 1 の個数が等しい連続する整数の組数

2014年11月26日 | ブログラミング

1~2014 までの数を 2 進数で表したときに,連続する 2 数の 1 の個数が同じであるようなペアは何組存在するか

連続する数のうち,(1, 2),(5, 6), (9, 10), ...
のように, (4(i-1)+1, 4(i-1)+2),i = 1, 2, ... の 2 数の 1 の個数が等しくなる。

よって,n までには ifelse((n-1)%%4, (n-1)%/%4+1, (n-1)%/%4) 組存在する

n = 2014 ならば,
> n = 2014
> ifelse((n-1)%%4, (n-1)%/%4+1, (n-1)%/%4)
[1] 504

504 組存在する

愚直なプログラムを書いて確かめるなら,

> func = function(n) {
+     count = 0
+     repeat {
+         count = count + n %% 2
+         n = n %/% 2
+         if (n == 0) return(count)
+     }
+ }
> sum(diff(sapply(1:n, func)) == 0)
[1] 504

コメント
  • X
  • Facebookでシェアする
  • はてなブックマークに追加する
  • LINEでシェアする

1~100にある素数を列挙

2014年11月26日 | ブログラミング

20 分で答よということなので,できるだけ無精をすることにすると...

library(gmp)
p = 1
repeat {
    p = nextprime(p)
    if (p > 100) break
    print(as.integer(p))
}

コメント
  • X
  • Facebookでシェアする
  • はてなブックマークに追加する
  • LINEでシェアする

排他論理和でパスカルの三角形もどき

2014年11月26日 | ブログラミング

「パスカルの三角形」は「右上の数と左上の数の和」を配置するが,「和」ではなく「排他的論理和」を使う場合を考える。
2014番目の「0」が出力されるのは何段目になるか?

規則性もあるだろうが,たかが 2014 番目なので,多めに見積もって,馬鹿正直なプログラムを書く。
それでも,解を得るのに 0.06 程度しかかからないのだから,これ以上の策を弄するのは無駄というものだ。

system.time({
m = 100
a = matrix(0, m, m+1)
a[1, 2] = 1
for (i in 2:m) {
    for (j in 2:(i+1)) {
        a[i, j] = xor(a[i-1, j-1], a[i-1, j])
    }
}

b = 1:m - rowSums(a)
p = which.min(2014 > cumsum(b))
print(p) # 解
print(sum(b[1:(p-1)])) # 念のための確認
print(sum(b[1:p])) # 念のための確認
})

[1] 75 # 75 段目
[1] 1980 # 74 段目の終わりまでに 1980 個
[1] 2047 # 75 段目の終わりまでに 2047 個

所要時間
   ユーザ   システム       経過  
     0.058      0.003      0.061

コメント
  • X
  • Facebookでシェアする
  • はてなブックマークに追加する
  • LINEでシェアする

妙な(?)数列の一般項

2014年11月26日 | ブログラミング

「どの桁にも 0, 3, 6, 9 が表れない」という条件を満たす正の整数を小さい順に並べて以下のような数列を作る。
 1, 2, 4, 5, 7, 8, 11, 12, 14, 15, 17, 18, 21, 22, ...
この数列の 30 番目の項は 58 である。では,この数列の 10^7 番目の項を求めよ。

n 番目の項を手計算で求める。
0, 3, 6, 9 を含まない数だけを考えるということは,
要するに 1, 2, 4, 5, 7, 8 という記号で表される数を,0, 1, 2, 3, 4, 5 という 5 つの数字で表される 6 進数を考えるということ

出現する数字 6 進数字
   1      0
   2      1
   4      2
   5      3
   7      4
   8      5

6 進数字を使って表示すると
1 桁のものは 6     個 0,1, 2, 3, 4, 5
2 桁のものは 6^2 個 ただし,00, 01, ..., 55 であることに注意
3 桁のものは 6^3 個 ただし,000, 001, ..., 555 であることに注意
4 桁のものは 6^4 個 以下同様
5 桁のものは 6^5 個
6 桁のものは 6^6 個
7 桁のものは 6^7 個
8 桁のものは 6^8 個
ここまでで,累計 2015538 個の数(項)である(10 進数で)
目的の 10^7 番目は,9 桁の 6 進数 000000000 を 1 番目として,10^7-2015538 = 7984462 番目の数,数としては 007984461(10 進数)
7984462 の 6 進表示(9 桁)は 443045034
これを逆変換すると 775178157 になる。これが 10^7 番目の項

ということで,プログラム化

func = function(n) { # n 番目の数を求める
  k = sum(n > cumsum(6^(1:8))) # k+1 桁の 6 進数の中にある
  m = sum(6^(1:k)) # k 桁までの 6 進数の個数の総数
  i = n - m - 1 # 求める数の k+1 桁の 6 進表記
  num = numeric(k+1)
  for (j in 1:(k+1)) {
    num[j] = i %% 6
    i = i %/% 6
    if (i == 0) break
  }
  as.numeric(paste(c(1, 2, 4, 5, 7, 8)[rev(num)+1], collapse=""))
}
func(10^7) # 775178155
func(10^6) # 44244455
func(10^5) # 1858755
func(10^4) # 115155
func(10^3) # 5455
func(10^2) # 255
func(3333) # 24244

時間が掛かるが,真っ正直に計算して,正しいことを確かめるプログラム

func0 = function(n) {
  count = 0
  for (i in 1:1e7) {
    a = unlist(strsplit(as.character(i), ""))
    if (all(! (a %in% c(0, 3, 6, 9)))) {
#     print(i)
      count = count+1
      if (count == n) break
    }
  }
  print(i)
}
func0(3333) # 24244
func0(10^2) # 255
func0(10^3) # 5455
func0(10^4) # 115155
func0(10^5) # 1858755

コメント
  • X
  • Facebookでシェアする
  • はてなブックマークに追加する
  • LINEでシェアする

PVアクセスランキング にほんブログ村

PVアクセスランキング にほんブログ村