int main() {
int ch[16];
REP(i,16) {
ch[i] = 0;
REP(k, 16)
if (k/4 == i/4 || k%4 == i%4)
ch[i] |= 1<<k;
}
string in;
int ref = 0;
REP(i, 4) {
cin >> in;
REP(j, 4)
if (in[j] == '+')
ref |= 1<<(4*i+j);
}
int ret = INF, bcomb = -1;
REP(comb, 1<<16) {
int ref_t = ref, cnt=0;
REP(i, 16)
if (comb >> i & 1)
ref_t ^= ch[i], ++cnt;
if (!ref_t && ret > cnt)
ret = cnt, bcomb = comb;
}
cout << ret << endl;
REP(i, 16)
if (bcomb >> i & 1)
cout << i/4+1 << " " << i%4+1 << endl;
return 0;
}
Search on the blog
2010年12月25日土曜日
ビット演算集大成の問題!?
クロージャとは何か?(2)
def seriesSum(n):
ret = 0
for x in range(1, n+1):
ret += x
return ret
def seriesSum(n):
ret = 0
for x in range(1, n+1):
ret += x*x
return ret
じゃあ、一般的に
def genSeriesSum(_f):
func = _f
def seriesSum(n):
ret = 0
for x in range(1, n+1):
ret += func(x)
return ret
return seriesSum
使うときは、どうするのでしょうか?
では、説明してみます。
def square(x):
return x*x
squareSum = genSeriesSum(square)
print squareSum(10)
どうでしょうか?
def genDeriverable(_f, _dx):
f = _f
dx = _dx
def deriverable(x):
return (f(x + dx) - f(x)) / dx
return deriverable
2010年12月24日金曜日
クロージャとは何か?(1)
2010年12月20日月曜日
包除原理とその実装
set<int> primes;
void fact(int n) {
FOR (i, 2, n) {
if (n % i == 0) {
primes.insert(i);
n /= i;
i = 1;
}
}
if (n > 1) primes.insert(n);
}
int solve(int n, int bit, VI &vec) {
int on = 0, mul = 1;
REP(i, 32)
if (bit >> i & 1)
++on, mul*= vec[i];
return (on % 2 ? 1 : -1) * n / mul;
}
int main() {
int n;
while (cin >> n, n) {
primes.clear();
fact(n);
int ret = 0;
vector<int>vec(ALL(primes));
REP(bit, 1<<vec.size()) {
if (!bit) continue;
ret += solve(n-1, bit, vec);
}
cout << n-1-ret << endl;
}
return 0;
}
2010年12月13日月曜日
C++でParse
char input[256];
int main() {
int h, m, s, v = 0;
double x = .0;
double t0 = .0, t1 = .0;
while (gets(input)) {
stringstream ss(input);
string s1 = "", s2 = "";
ss >> s1 >> s2;
sscanf(s1.c_str(), "%02d:%02d:%02d", &h, &m, &s);
t1 = h + m/60.0 + s/3600.0;
x += (t1 - t0) * v;
t0 = t1;
if (s2 != "")
sscanf(s2.c_str(), "%d", &v);
else
printf("%02d:%02d:%02d %.2lf km\n", h, m, s, x);
}
return 0;
}
2010年12月11日土曜日
末尾再帰について
In traditional recursion, the typical model is that you perform your recursive calls first, and then you take the return value of the recursive call and calculate the result. In this manner, you don't get the result of your calculation until you have returned from every recursive call.
In tail recursion, you perform your calculations first, and then you execute the recursive call, passing the results of your current step to the next recursive step. This results in the last statement being in the form of "(return (recursive-function params))" (I think that's the syntax for Lisp). Basically, the return value of any given recursive step is the same as the return value of the next recursive call.
The consequence of this is that once you are ready to perform your next recursive step, you don't need the current stack frame any more. This allows for some optimization. In fact, with an appropriately written compiler, you should never have a stack overflow snicker with a tail recursive call. Simply reuse the current stack frame for the next recursive step. I'm pretty sure Lisp does this.
ざっくり日本語で言うと、
- 普通に再帰を書くと、再帰して呼び出した結果を利用して、値を計算するという流れになる。
- 末尾再帰では、一番最後に自身を再帰する。最初に計算をして、その値を呼び出し先に伝えるという手法を取る。
- 末尾再帰を用いると、現在使用しているスタック構造をそのまま再帰呼び出し先で再利用することができ、スタックの節約ができる。
上のコードは階乗を求めるソースです。普通は、上のように書くでしょう。。
int factorial(int n) {
if (!n)
return 1;
return n * factorial(n-1);
}
かるく衝撃を覚えるほどのソースコードです。returnするときには、現在の関数のスタックは必要じゃなくなってますね。。ちょっと動的計画を彷彿とさせるような感じですが。。
int factorial2(int n, int acc=1) {
if (!n)
return acc;
return factorial2(n-1, n*acc);
}
引用サイト: http://stackoverflow.com/questions/33923/what-is-tail-recursion
Emacs 入門(2)
2010年12月8日水曜日
Emacs 入門
2010年12月4日土曜日
いろいろな距離概念
- ユークリッド距離
- マンハッタン距離
- チェビシェフ距離
これは、ベクトル空間でいう距離や3次元空間における一般的な距離と同じである。
2010年12月1日水曜日
ビットDPにチャレンジ
tspの部分は、最後に0に戻ってくるような形にしたくて、ちょっとスパゲッティ気味です。。
typedef pair<int, int>point;
point beeper[12];
int network[12][12];
int dp[12][1<<12];
int n;
void tsp(int p, int bit) {
if (bit+1 == 1<<n+1)
return;
REP(i, n+1) {
if (bit >> i & 1) continue;
int mask = bit | (1 << i);
if (!i && mask != (1<<n+1)-1) continue;
if (dp[i][mask] > dp[p][bit] + network[p][i]) {
dp[i][mask] = dp[p][bit] + network[p][i];
tsp(i, mask);
}
}
}
int main() {
int sc, xsize, ysize;
int x, y;
cin >> sc;
while (sc--) {
cin >> xsize >> ysize;
cin >> x >> y;
beeper[0] = point(--x, --y);
cin >> n;
REP(i, n) {
cin >> x >> y;
beeper[i+1] = point(--x, --y);
}
REP(i, n+1)REP(j, n+1)
network[i][j] = ABS(beeper[i].first - beeper[j].first)
+ ABS(beeper[i].second - beeper[j].second);
REP(i,n+1)REP(j, 1<<n+1)
dp[i][j] = INF;
dp[0][0] = 0;
tsp(0, 0);
cout << "The shortest path has length " << dp[0][(1<<n+1)-1] << endl;
}
return 0;
}
注意)但し、ビットDPでも指数オーダーなので、この方法で解けるのはnが小さい場合のみ。
void tsp(int p, int bit) {
REP(i, n+1) {
if (bit >> i & 1) continue;
int mask = bit | (1 << i);
if (dp[i][mask] > dp[p][bit] + network[p][i]) {
dp[i][mask] = dp[p][bit] + network[p][i];
tsp(i, mask);
}
}
}