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);
}
}
}
2010年11月27日土曜日
空間認知能力
int removeCubes(vector<string> A, vector<string> B, vector<string> C) {
// A x-y
// B x-z
// C y-z
int sz = (int)A.size();
memset(cube, 1, sizeof(cube));
REP(i, sz) {
REP(j, sz) {
if (A[i][j] == 'N') REP(k, sz) cube[i][j][k] = 0;
if (B[i][j] == 'N') REP(k, sz) cube[i][k][j] = 0;
if (C[i][j] == 'N') REP(k, sz) cube[k][i][j] = 0;
}
}
// valid-check
REP(i, sz) {
REP(j, sz) {
if (A[i][j] == 'Y') {
int t = 0;
REP(k, sz)
t += cube[i][j][k];
if (!t) return -1;
}
if (B[i][j] == 'Y') {
int t = 0;
REP(k, sz)
t += cube[i][k][j];
if (!t) return -1;
}
if (C[i][j] == 'Y') {
int t = 0;
REP(k, sz)
t += cube[k][i][j];
if (!t) return -1;
}
}
}
int ret = 0;
REP(i, sz)REP(j,sz)REP(k,sz)
if (!cube[i][j][k])
++ret;
return ret;
}
ほう、逆の発想をすることで、判定のところがシンプルに書けるわけか。。結構このコード理解するのに時間かかりました(笑)
int removeCubes(vector<string> A, vector<string> B, vector<string> C) {
int sz = (int)A.size();
bool a[sz][sz], b[sz][sz], c[sz][sz];
memset(a, 0, sizeof(a));
memset(b, 0, sizeof(b));
memset(c, 0, sizeof(c));
int ret = sz*sz*sz;
REP(i,sz)REP(j,sz)REP(k,sz)
if (A[i][j] == 'Y' && B[i][k] == 'Y' && C[j][k] == 'Y') {
--ret;
a[i][j] = 1;
b[i][k] = 1;
c[j][k] = 1;
}
REP(i,sz)REP(j,sz) {
if (A[i][j] == 'Y' && !a[i][j]) return -1;
if (B[i][j] == 'Y' && !b[i][j]) return -1;
if (C[i][j] == 'Y' && !c[i][j]) return -1;
}
return ret;
}
2010年11月24日水曜日
誤差にまつわるエトセトラ
まず、以下のコードを実行してみましょう。
#define EPS 1e-7
int main() {
// case 1
double x = 1e16;
printf("%lf\n", x + 1);
// case 2
double y1 = 123456123456.1234588623046875;
double y2= 123456123456.1234741210937500;
printf("%d\n", ABS(y1 - y2) < EPS);
printf("%d\n", ABS(y1 - y2) < EPS * y1);
// case 3
double z1 = 1e-1072;
double z2 = -1e-1072;
printf("%d\n", ABS(z1 - z2) < EPS * z1);
return 0;
}
結果は以下のようになります。
>10000000000000000.000000
0
>1
>0
>1.000000
まず、case1から見ていきましょう。
10000000000000000.000000に1を足しても
10000000000000001.000000にはなりません。
これは、doubleの有効桁数が2^52 ~10^15だからです。最初の15桁以下は丸められてしまいます。逆に言うと、10^15以下の整数ならdoubleで正確に表すことができます。
この辺の話は昔投稿しているので、こちらをご覧ください。
次に、case2です。
これは、おもしろいです。y1とy2をビット列で表すとそれぞれ以下のようになります。
01000010 00111100 10111110 10001110 11110010 01000000 00011111 10011011
01000010 00111100 10111110 10001110 11110010 01000000 00011111 10011100
実は、この2つの数は、doubleの世界では連続する数値です。それにも関らず、(y1-y2)は1e-5程度です。
これは、大変です。連続する値なので、ほんの少しのエラーで、ある値がもう片方の値になりえます。
数値計算を実施する際は、この2つは、同じ値とみなしてよいでしょう。
しかし、ABS(y1-y2) < eps (eps = 1e-7)
2010年11月20日土曜日
C++で関数型プログラミング:accumulate編
#include<numeric>
#define INF 999999999
int x[] = {1,2,3,4,5,6,7,8,9,10};
int y[] = {15, 12, 99, 27};
int z[] = {10, 20, 150, 100};
int w[] = {1,3,10,100, -12, 2, 4};
int multiply(int x, int y) {
return x*y;
}
int gcd(int a, int b) {
if (!b)
return a;
return gcd(b, a%b);
}
int lcd(int a, int b) {
return a*b/gcd(a,b);
}
int myMin(int a, int b) {
return (a < b) ? a : b;
}
int myMax(int a, int b) {
return (a > b) ? a : b;
}
int main() {
cout << accumulate(x, x+SIZE(x), 0) << endl;
cout << accumulate(x, x+SIZE(x), 1, multiply) << endl;
cout << accumulate(y, y+SIZE(y), *y, gcd) << endl;
cout << accumulate(z, z+SIZE(z), *z, lcd) << endl;
cout << accumulate(w, w+SIZE(w), INF, myMin) << endl;
cout << accumulate(w, w+SIZE(w), -INF, myMax) << endl;
return 0;
}
- input は畳み込み対象の開始位置
- lastは畳み込み対象の終了位置
- initは初期値
- binary_opは引数を2つもつ関数のポインタ
2010年11月15日月曜日
トポロジカルソート
- トポロジー 幾何学的な相対位置、ネットワークの接続状況など
- エントロピー 物事の煩雑さ
- オントロジー 物事の概念を意味・関係などで定義したもの
bool dn[64];
class CorporationSalary {
public:
long long totalSalary(vector<string> relations) {
memset(dn, 0, sizeof(dn));
VI idx;
int sz = relations.size();
while (accumulate(dn, dn+sz, 0) < sz) {
REP(i, relations.size()) {
if (dn[i]) continue;
bool lst = true;
REP(j, relations[i].size()) {
if (dn[j]) continue;
if (relations[i][j] == 'Y') {
lst = false;
break;
}
}
if (lst) {
idx.PB(i);
dn[i] = 1;
}
}
}
long long ret = 0LL;
long long sl[sz];
fill(sl, sl+sz, 0LL);
REP(i, sz) {
long long m = 0LL;
REP(j, sz) {
if (relations[idx[i]][j] == 'Y')
m += sl[j];
}
sl[idx[i]] = m ? m : 1;
ret += sl[idx[i]];
}
return ret;
}
};
2010年11月14日日曜日
知ってると便利なSTL(5) fill, fill_n
- fill
- fill_n
int main() {
int x[10];
vector<string> names(7);
fill(x, x+10, 100);
fill(names.begin(), names.end(), "ken-ken");
REP(i, 10)
printf("%d\n", x[i]);
REP(i, 7)
printf("%s\n", names[i].c_str());
return 0;
}
int main() {
int x[10];
vector<int> y(10);
char z[10];
fill_n(x, SIZE(x), 10);
fill_n(y.begin(), 10, -1);
fill_n(z, 10, 'o');
REP(i, 10)
printf("%d\n", x[i]);
REP(i, 10)
printf("%d\n", y[i]);
REP(i, 10)
printf("%c\n", z[i]);
return 0;
}
2010年11月10日水曜日
初めての・・・・Hard AC!
class Prb {
public:
int sweet;
int x;
int y;
int len;
Prb(int s, int _x, int _y, int l) {
sweet = s;
x = _x;
y = _y;
len = l;
}
bool operator<(const Prb &prb) const {
if (this->y != prb.y)
return this->y < prb.y;
if (this->x != prb.x)
return this->x < prb.x;
return this->sweet < prb.sweet;
}
};
int dp[64];
bool dn[64];
vector<Prb> pp;
class GetToTheTop {
public:
int collectSweets(int K, vector<int> sweets, vector<int> x, vector<int> y, vector<int> stairLength) {
pp.clear();
memset(dp, 0, sizeof(dp));
pp.PB(Prb(0, 1, 0, 11000));
REP(i, sweets.size())
pp.PB(Prb(sweets[i], x[i], y[i], stairLength[i]));
SORT(pp);
// same y
FOR (i, 1, pp.size()) {
if (pp[i].y != pp[i-1].y)
continue;
int l1 = pp[i].x, r1 = l1+pp[i].len;
int l2 = pp[i-1].x, r2 = l2+pp[i-1].len;
double r;
if (l1 >r2)
r = dist(l1, 0, r2, 0);
else
r = dist(l2, 0, r1, 0);
if (r <= K) {
pp[i].sweet += pp[i-1].sweet;
pp[i-1].sweet = -1;
}
}
FOR (i, 1, pp.size())
if (pp[pp.size()-1-i].sweet == -1)
pp[pp.size()-1-i].sweet = pp[pp.size()-i].sweet;
int posy = 0;
REP(i, pp.size()) {
if (posy != pp[i].y) {
posy = pp[i].y;
meanSameY(i, posy, pp.size(), K);
}
if (i && !dp[i])
continue;
int l1 = pp[i].x;
int r1 = l1 + pp[i].len;
REP(j, pp.size()) {
if (i == j) continue;
if (pp[i].y >= pp[j].y) continue;
int l2 = pp[j].x;
int r2 = l2 + pp[j].len;
double r;
if (r1 < l2) r = dist(r1,pp[i].y, l2, pp[j].y);
else if (l1 > r2) r = dist(l1,pp[i].y, r2, pp[j].y);
else r = dist(0, pp[i].y, 0, pp[j].y);
if (r <= K)
dp[j] = max(dp[j], dp[i] + pp[j].sweet);
}
}
return *max_element(dp, dp+pp.size());
}
double dist(int x1, int y1, int x2, int y2) {
return sqrt((x1-x2)*(x1-x2) + (y1-y2)*(y1-y2));
}
void meanSameY(int pos, int h, int sz, int K) {
VVI idx;
VI tmp;
FOR (i, pos, sz) {
if (i >= sz pp[i].y != h) {
idx.PB(tmp);
tmp.clear();
break;
}
if (pp[i].x - (pp[i-1].x + pp[i-1].len) > K) {
idx.PB(tmp);
tmp.clear();
}
tmp.PB(i);
}
REP(i, idx.size()) {
int ret = 0;
tmp = idx[i];
REP(j, tmp.size())
ret = max(ret, dp[tmp[j]]);
REP(j, tmp.size())
dp[tmp[j]] = ret;
}
}
};
2010年11月9日火曜日
ヒープを作ってみよう!
class myHeap {
public:
myHeap() {
this->tail = 0;
}
void add(int n) {
hp[tail++] = n;
int pos = tail-1;
while (pos) {
if (hp[(pos-1)/2] < hp[pos])
swap(hp[(pos-1)/2], hp[pos]);
pos = (pos-1)/2;
}
}
int pop() {
if (isEmpty()) {
cerr << "Heap is empty!" << endl;
return -1;
}
int ret = hp[0];
hp[0] = hp[--tail];
int pos = 0;
while (2 * pos + 2 <= tail) {
if (hp[pos] > max(hp[2*pos+1], hp[2*pos+2]))
break;
if (hp[2*pos+1] > hp[2*pos+2]) {
swap(hp[pos], hp[2*pos+1]);
pos = 2*pos+1;
}
else {
swap(hp[pos], hp[2*pos+2]);
pos = 2*pos+2;
}
}
return ret;
}
bool isEmpty() {
return tail <= 0;
}
private:
int hp[1<<10];
int tail;
};
int main() {
myHeap hp = myHeap();
REP(i, 100)
hp.add(rand() % 1000);
while (!hp.isEmpty())
printf("%d\n", hp.pop());
return 0;
}
- 最大値の参照は、O(1)
- push()およびpop()は、O(log n)
2010年11月7日日曜日
部分和を列挙する
- lucky numberを探索してキャッシュすること
- nがlucky numberのみで構成できるかどうかDPを使って判定すること
- 構成出来る場合は、その解を問題の定義どおりに列挙すること
int dp[1000001];
class TheSumOfLuckyNumbers {
public:
void makeLucky(vector<int>&A, int x, int n) {
if (x)
A.PB(x);
if (x * 10 + 4 <= n)
makeLucky(A, x * 10 + 4, n);
if (x * 10 + 7 <= n)
makeLucky(A, x * 10 + 7, n);
}
vector<int> sum(int n) {
VI A;
makeLucky(A, 0, n);
SORT(A);
// DP
EACH(itr, A) {
dp[*itr] = 1;
REP(i, n+1) {
if (!dp[i])
continue;
if (i + *itr > n)
continue;
if (!dp[i + *itr] || dp[i + *itr] >= dp[i] + 1)
dp[i + *itr] = dp[i] + 1;
}
}
VI ret;
int pos = n;
// Greedy
EACH(itr, A) {
while (dp[pos] - dp[pos - *itr] == 1 && pos) {
if (!dp[pos - *itr] && pos - *itr)
break;
ret.PB(*itr);
pos -= *itr;
if (pos - *itr < 0) break;
}
if (!pos)
break;
}
return ret;
}
};
- 問題のレベル分けがきちんとなされている
- 赤い人のコードや解説(editorial)が読める
- すべての問題が種類別にカテゴライズされている。
2010年11月4日木曜日
知ってると便利なSTL(4) swap
int main() {
int a = 10;
int b = 3;
swap(a, b);
printf("%d %d\n", a, b);
return 0;
}
これは、かなり便利そう。
int main() {
int x[] = {3,4,5,1,2,10,9,7,8,6};
REP(i, 10)
FOR (j, i, 10)
if (x[i] > x[j])
swap(x[i], x[j]);
REP(i, 10)
printf("%d ", x[i]);
return 0;
}
2010年10月31日日曜日
知ってると便利なSTL(3) max_element, min_element
#define SIZE(buff) (sizeof(buff)/sizeof(buff[0]))これが何気に面倒臭かったりします。最大値だけならそうでもない(ループ内でmax使えばいいだけ)ですが、最大値を与えるindexを求める場合は、ちょっとだけソースコードが長くなってしまい面倒です。
#define REP(i, n) for(int i=0; i<(int)(n); i++)
int main() {
int x[] = {1,3,5,7, 10, 0, 4, 20, 4, 6};
int mx = -1;
REP(i, SIZE(x)) {
if (mx == -1 || x[mx] < x[i])
mx = i;
}
printf("max element=%d, max value=%d\n", mx, x[mx]);
return 0;
}
int main() {かなりシンプルですね。戻り値はiteratorですが、配列の場合はポインタとの引き算もできるみたいです。これを使えば、上の例のように最小値(最大値)を与えるindexも簡単に出ますね!
int x[] = {1,3,5,7, 10, 0, 4, 20, 4, 6};
// search max
int *mx = max_element(x, x+SIZE(x));
printf("max element=%d, max value=%d\n", mx - x, *mx);
// search min
int *mn = min_element(x, x+SIZE(x));
printf("min element=%d, min value=%d\n", mn - x, *mn);
return 0;
}
2010年10月30日土曜日
Pythonで数値計算
- 基本はC++
- 多倍長、正規表現の文字列処理を用いる場合はJAVA
- 数値計算、ネットワークプログラミングはPython
2010年10月27日水曜日
PKU150問突破~~!
- 変数の名前はなるべく1文字にする
- 変数はグローバル変数として宣言する
- なるべく改行しない
- マクロを駆使する
2010年10月19日火曜日
久々の仕事でコーディング
- libファイルは、コンパイル時にリンクされる。実行時にexeファイル単体で実行できるけど、ファイル容量が重くなる。
- dllファイルは、実行時に動的にリンクする。ファイル容量を小さくできるが、実行時に参照しているdllファイルを配置しなければならない。複数アプリから同様の機能を使用する場合は、dllファイルを用いるとメモリの節約ができる。
- hファイルは、宣言のみ書いたファイル。libファイルやdllファイルを使用する場合は、使用するファイル内に含まれるクラス、関数を宣言しておかなければならない。
2010年10月16日土曜日
Pythonで美人時計の画像を自動取得
import sys
import os
import urllib2
argvs = sys.argv
img_path = argvs[1]
output = "/home/kenji/python/img/" + os.path.basename(img_path)
print "downloading from", img_path, "to", output, "......"
opener = urllib2.build_opener()
req = urllib2.Request(img_path)
req.add_header('Referer', "http://bijint.com/jp")
file = open(output, 'wb')
file.write(opener.open(req).read())
file.close()
2010年10月15日金曜日
PythonでHTML解析
- yahooのhtml ソースを取得する
- 自分のbloggerのページから張っているリンク先のページを列挙する
'''urllib2というモジュールを使うと簡単にhtmlコンテンツを取得できます。あとは、文字コードを取得してそれをデコードすればOK。
sample 1
Get html contents and automatically decode its strings
'''
import urllib2
res = urllib2.urlopen("http://yahoo.co.jp")
charset = res.headers.getparam('charset')
html = res.read().decode(charset)
print html
'''これは、ちょっと汚いです。BeautifulSoupというHTMLパーサライブラリがあるのでそれを使うともっとスマートに書けそうです。
sample 2
Get html contents and get the link from the page
'''
import urllib2
import re
def getHrefAddress(x):
x = re.sub(r'^href="|^href=\'', '', x)
x = re.sub(r'"$|\'$', '', x)
if re.match(r'http://', x) == None or re.match(url, x):
x = None
return x
url = "http://techtipshoge.blogspot.com/"
res = urllib2.urlopen(url)
html = res.read()
links = re.findall(r'href=".+?"|href=\'.+?\'', html)
links = map(getHrefAddress, links)
links = filter(None, links)
for link in links:
print link
2010年10月10日日曜日
最短経路アルゴリズムまとめ
Bellman-Ford | Dijkstra(matrix) | Dijkstra(list) | Warshall-Floyd | |
Applicable Problem | 単一始点最短路問題 | 単一始点最短距離問題 | 単一始点最短距離問題 | 全頂点対最短経路問題 |
Input Data Form | 隣接リスト | 隣接行列 | 隣接行列 | 隣接行列 |
Idea | ・すべての距離を毎回更新 | ・確定した接点に接続する接点の距離のみ更新 | ・priority_queueを用いて確定接点の探索を高速化 ・暫定距離の更新も実在する枝の数だけで実施 | ・逐次通過可能な接点集合を増加させながら解く |
Calculation Amount | ・1回のループではE本の枝を走査 ・負の閉路が含まれないければループは高々V-1回で終わる(最短パスに含まれる頂点数は最高でもV-1であるため) ・O(E * V) | ・外側のループ一回につき一つの接点が確定 ・ループ内部では、最小値検索、V個の距離更新を行う ・O(V^2) | ・値の更新はO(E)で実施できる ・値の取り出しはO(logV)で実行でき、O(E)回程度実行される ・O(ElogV) | ・通過できる接点は1つずつ増やす ・隣接行列の値を毎回すべて更新する ・O(V^3) |
Feature | ・負の辺が含まれていても解ける ・負の閉路がある場合は更新が無限に続くため解けない。 (※無効グラフの場合は辺も閉路になるので注意) ・上記の性質を利用すれば負の閉路を検出できる | ・負の辺が含まれている場合は解けない ・Bellman-Fordの無駄な計算を省略した改良バージョンと解釈できる | ・負の辺が含まれている場合は解けない ・EはV^2個に比べて小さい場合が多いため、matrixバージョンの無駄を省略し高速に計算できる | ・負の辺が含まれていても解ける ・実装が簡単なので計算量に余裕があれば、単一始点問題でもWarshall-Floydを利用するとよい |
2010年10月7日木曜日
スマートグリッド、そしてスマートシティへ
スマートグリッドとは日本語に訳すと『次世代伝送網』のことで、電力の配送システムを供給・需要の両側から制御し最適化しようという試みである。経済面からも環境面からも有益なソリューションであるため、産官学が協力し研究・計画を実施している。
スマートグリッドをさらに発展させて、『スマートシティ』という概念も現れた。これは伝送網だけではなく、街そのものをスマート化しましょうというアイディアである。
簡単に言うと、“自然に優しく、無駄遣いをしないような賢い街づくりをコンピュータを使ってやってみましょう!”ということだ。具体例を挙げれば、
- 太陽光発電を自宅に取り入れて、
- 自動車は電気自動車に変えて、
- 交通渋滞が起こらないように交通量を制御して、
- 配電はもちろんスマートグリッドで、
- 電気の使用状況は常時モニタリングして
- ・・・
日本では、横浜(参考ページ参照)、豊田市、京都府、北九州市がスマートシティのモデル都市として選ばれました。うちの会社もがんばってるみたい!ガンバレー!!!
もともとスマートグリッド構想は、オバマ政権がグリーンニューディール政策の柱として打ち出したもの。さらに起源をたどれば、2003年のアメリカ大停電を経験して、停電を起こしにくい配電網を構築しようというのがそもそもの動機付けだったのかもしれない。それが、エコブームの波に乗り、今日の“スマート○○”ブームを作り上げたのかも。。
とりあえず、この『スマートシティ』、IT関連の会社にとってはとてつもないビジネスチャンスです。市場規模は今後30年累計で3100兆円と言われている@_@
私の会社も、スマートグリッドを『IFRS』と並ぶ今後の二大ビジネスチャンスとして捉えているようです。もちろん、IT会社の他にも自動車会社、電力・ガス会社、電気機器メーカーにとっても大きなビジネスチャンスです。今後、“スマート○○”のパワーで日本の、そして世界の景気が上向くことを期待しましょう!
あーーー、給料あがれー、あがれーー笑。
引用:
http://www.kankyo-business.jp/topix/smartgrid_01.html
http://ja.wikipedia.org/wiki/%E3%82%B9%E3%83%9E%E3%83%BC%E3%83%88%E3%82%B0%E3%83%AA%E3%83%83%E3%83%89
http://blog.goo.ne.jp/thinklive/e/05b191a8ecf7f535934185843f745355
参考ページ:
http://www-06.ibm.com/innovation/jp/smarterplanet/cities/
http://www.jftc.or.jp/shoshaeye/contribute/contrib2010_07e.pdf
2010年10月5日火曜日
ショートコーディング(1) : if文はお嫌い!?
int main() {何をやっているか分かりますか?
REP(i, 10)
i % 2 && printf("%d\n", i);
REP(i, 10)
i % 3 || printf("%d サン!\n", i);
REP(i, 10)
i ? printf("%lf\n", 1.0 / i) : puts("Zero Devider");
return 0;
}
分岐文 | 対応するショートコーディング文 |
if(hogehoge) do | hogehoge && do |
if(!hogehoge) do | hogehoge || do |
if(hogehoge) do1 else do2 | hogehoge ? do1 : do2 |
2010年10月2日土曜日
ビット演算で遊ぼう
void getBin(int n, char bin[]) {
REP (i, 16)
bin[15 - i] = (n >> i & 1) + '0';
bin[16] = '\0';
}
int main() {
int n, bit;
char calc, bin[16 + 1];
cout << "Input an integer." << endl;
cin >> n;
getBin(n, bin);
printf("%s\n", bin);
// Input one of the manipulations below:
// q exit
// u bit change bit-th bit to '1'
// d bit change bit-th bit to '0'
// x bit reverse bit-th bit
// c reverse all bits
// where q, u, d, x and c are characters themselves, bit is an integer and 0-based.
while (cin >> calc) {
switch (calc) {
case 'q':
cout << "Bye!" << endl;
return 0;
case 'u':
cin >> bit;
n |= 1 << bit;
break;
case 'd':
cin >> bit;
n &= ~(1 << bit);
break;
case 'x':
cin >> bit;
n ^= 1 << bit;
break;
case 'c':
n = ~n;
break;
default:
cerr << "Syntax Error." << endl;
cerr << "Try again." << endl;
continue;
}
getBin(n, bin);
printf("%s\n", bin);
}
return 0;
}
2010年9月29日水曜日
ポワソン分布
- 事象はいかなる時点でもランダムに発生しうる。
- 与えられた時間区間での事象の発生は,それと重複しない他の区間に対して独立である。
- 微小時間⊿tにおける事象の発生確率は⊿tに比例して小さくなっている。
- 微小時間⊿tの間に事象が2回以上発生する確率は無視できる。
- 時間tの間に当該事象が発生する平均発生回数λがおおむね5以下である。
2010年9月26日日曜日
TopCoder惨敗とPKU祝杯!
2010年9月24日金曜日
エラトステネスの脅威
void getPrime1(int n) {
VI prime;
FOR (i, 2, n) {
bool isPrime = true;
FOR (j, 2, i) {
if (i % j == 0) {
isPrime = false;
break;
}
}
if (isPrime)
prime.PB(i);
}
printf("%d\n", prime.size());
}
void getPrime2(int n) {
VI prime;
FOR (i, 2, n) {
bool isPrime = true;
FOR (j, 2, (int)sqrt(i) + 1) {
if (i % j == 0) {
isPrime = false;
break;
}
}
if (isPrime)
prime.PB(i);
}
printf("%d\n", prime.size());
}
void getPrime3(int n) {
bool *isPrime = new bool[n];
VI prime;
memset(isPrime, 1, sizeof(bool) * n);
for (int i = 2; i < sqrt(n) + 1; i++) {
if (!isPrime[i])
continue;
for (int j = i + i; j < n; j += i)
isPrime[j] = 0;
}
FOR(i, 2, n)
if (isPrime[i])
prime.PB(i);
delete [] isPrime;
printf("%d\n", prime.size());
}
#include <sys/time.h>
inline double gettimeofday_sec() {
struct timeval t;
gettimeofday(&t, NULL);
return (double) t.tv_sec + (double) t.tv_usec * 1e-6;
}
int main() {
double s = gettimeofday_sec();
getPrime1(1000000);
printf("%lf\n", gettimeofday_sec() - s);
s = gettimeofday_sec();
getPrime2(1000000);
printf("%lf\n", gettimeofday_sec() - s);
s = gettimeofday_sec();
getPrime3(1000000);
printf("%lf\n", gettimeofday_sec() - s);
return 0;
}
アルゴリズム | オーダー | 実行時間[s] |
getPrime1 | n^2 | 157.9 |
getPrime2 | n^1.5 | 6.943 |
getPrime3 | n | 0.016 |
2010年9月22日水曜日
多倍長演算 --doubleの精度!?
- doubleの最大値、最小値
- doubleの精度
- 丸め誤差
#include <float.h>
#define EXP_MAX 2046 // 2047 is booked for exception procedure
#define EXP_MIN 1 // 0 is booked for exception procedure
#define EXP_BIAS 1023 // The biased exponent range: [-1022, 1023]
#define SIG_BIT 52 // significand bits
int main() {
// max
double dblmax = pow(2.0, EXP_MAX - EXP_BIAS);
double significand = 1.0;
REP(i, SIG_BIT)
significand += pow(2.0, -(i+1));
dblmax *= significand;
printf("dblmax = %e, DBL_MAX = %e\n", dblmax, DBL_MAX);
// min
double dblmin = pow(2.0, EXP_MIN - EXP_BIAS);
printf("dblmin = %e, DBL_MIN = %e\n", dblmin, DBL_MIN);
return 0;
}
int main() {
double min_significand = pow(2.0, -SIG_BIT);
printf("%.16f\n", min_significand);
double x = 1e15 + 1.0;
double y = 1e16 + 1.0;
printf("%.1lf\n", x);
printf("%.1lf\n", y);
}
double getSigVal(LL sigbit) {
double ret = 1.0;
REP(i, SIG_BIT) {
if ((sigbit >> SIG_BIT - 1 - i) & 1)
ret += pow(2.0, -(i+1));
}
return ret;
}
double getDoubleVal(int exp, LL sigbit) {
return getSigVal(sigbit) * pow(2.0, exp - EXP_BIAS);
}
int main() {
double x = 0.1;
LL sig, sigl, sigr;
int expo = 1;
while (pow(2.0, expo + 1 - EXP_BIAS) <= x)
expo++;
sigl = 0LL;
sigr = (1LL << 52) - 1LL;
sig = (sigl+ sigr) / 2;
REP(i, 200) {
double val = getDoubleVal(expo, sig);
if (ABS(val - x) < 1e-18)
break;
else if (val > x)
sigr = sig;
else
sigl = sig;
sig = (sigl + sigr)/2;
}
printf("significand = %lld, exponent = %d\n", sig, expo);
printf("0.1 is expressed something like %.18lf on the PC\n", getDoubleVal(expo, sig));
return 0;
}
2010年9月21日火曜日
配列を関数に渡す
/*
* int address
*/
void func1(int n) {
printf("The address of input is %d.\n\n", &n);
}
/*
* buffer address
*/
void func2(int n[]) {
printf("The address of input is %d.\n\n", n);
}
/*
* STL address
*/
void func3(vector<int> n) {
printf("The address of input is %d.\n\n", &n);
}
/*
* class address
*/
class Human{
public:
int age;
string name;
};
void func4(Human n) {
printf("The address of input is %d.\n\n", &n);
}
int main() {
int a;
printf("The address of input is %d.\n", &a);
func1(a);
int b[10];
printf("The address of input is %d.\n", b);
func2(b);
vector<int> c;
printf("The address of input is %d.\n", &c);
func3(c);
Human d;
printf("The address of input is %d.\n", &d);
func4(d);
return 0;
}
int main() {
int x[3][3][3];
REP(i, 3)
REP(j, 3)
REP(k, 3)
printf("%d\n", &x[i][j][k]);
return 0;
}
void func5(int n[][10]) {
REP(i, 10)
REP(j, 10)
printf("%d%c", n[i][j], (j==9) ? '\n' : ' ');
return;
}
int main() {
int buf[10][10];
memset(buf, 0, sizeof(buf));
func5(buf);
return 0;
}
2010年9月18日土曜日
IFRS対応でITバブル!?
影響を受ける業務 | 変更が必要なシステム |
売上計上基準の変更 | 販売管理システム |
棚卸資産の範囲/原価算定方法の変更 | 購買管理システム/在庫管理システム |
固定資産の減価償却の扱いの変更 | 固定資産管理システム |
リース取引の根本的な変更 | リース管理システム |
未消化有給休暇の費用計上 | 人事給与システム |
2010年9月14日火曜日
知ってると便利なSTL(2) pair
int main() {
vector<pair<int, int> >birthday(20);
REP(i, 20)
birthday[i] = MP(rand() % 12 + 1, rand() % 30 + 1);
SORT(birthday);
REP(i, 20)
printf("%02d/%02d is My Birthday.\n", birthday[i].first, birthday[i].second);
return 0;
}
何か気付きましたか?
int main() {
vector<pair<string, string> >name(10);
name[0] = MP("Tanaka", "Ai");
name[1] = MP("Yamada", "Taro");
name[2] = MP("Yamada", "Hanako");
name[3] = MP("Okada", "Yusuke");
name[4] = MP("Yamaguchi", "Satoshi");
name[5] = MP("Suzuki", "Ichiro");
name[6] = MP("Suzuki", "Jiro");
name[7] = MP("Suzuki", "Saburo");
name[8] = MP("Suzuki", "Shiro");
name[9] = MP("Oda", "Nobuo");
SORT(name);
EACH(itr, name)
cout << "I'm " << itr->first << " " << itr->second << endl;
return 0;
}
2010年9月12日日曜日
TOEIC受験
- ちゃんと問題の番号を確認する!!(超基本(笑))
- これが正解と思ったらすぐにマークする!!
2010年9月11日土曜日
コンマ演算子
- ループの終了判定が標準入力から入力したものに依存するとき、breakを使わずに簡単に書ける。
- ループの括弧を省略することができる。(Pythonみたい。)
int main() {
int L, M, s, e;
while (scanf("%d %d", &L, &M), L++ && M) {
REP(i, M)
scanf("%d %d", &s, &e),
L -= e-s+1;
printf("%d\n", L);
}
return 0;
}