Codeforces Round #176 (Div. 1) D. Tourists

JOIerお家芸感。なんかこれはJOIerは結構見た瞬間簡単だなあと思う気がする。おそらくDではない。

 

原点にある点がn個あり、i個目の点は時刻q[i]に原点を出発し、x軸の正方向に沿って速さ1で進む。また、それとは別にm個の線分が存在して、i番目の線分は時刻t[i]に区間[l[i], r[i]]を覆うように一瞬の内に出現する。各点について、点が線分に覆われながら移動している時間の長さを求めよ。

 

なんか本当に簡単で、div1Dにしては簡単だと思うんだけど、1つの線分(l, r, t)に注目した時、q[i] >= t-lであるような点iはその線分によって、r-l秒覆われていることになる。そして、これはどう見てもqに関して単調性がある、すなわち、q[j] >= q[i] >= t-lであれば、点jもr-l秒覆われることになるから、点をq[i]で昇順にsortしておけば、二分探索により、r-l秒覆われる点が全て分かる上、imos法を用いれば、全ての線分について考えたときの具体的な秒数の合計も一瞬で分かる。ここで少し怖くなるのは、t-r+1 <= q[i] < t-lであるような点iについては、点が移動している途中で線分が出現するので、具体的には、q[i]+r-t秒だけ微妙に覆われることになる。しかしこれも同様に二分探索とimos法によって対応可能で、どうするかというと、二分探索でt-r+1 <= q[i] < t-lを満たすiの範囲を求めた上で、定数r-tを普通のimos法で計算(A[i]にi番目の点のこの定数に関する累積和が入るとする)、定数1をimos法で計算する(P[i]にこの累積和が入るとする)と、微妙に覆われた時間の累計はP[i]*q[i] + A[i]で求まる。1次関数の累積を求めているイメージ。基本的にはこれだけなんだけど、後は線分に重複があるところだけ解決しないといけない。これは、各座標において、その座標を覆う線分の内、tが最小であるものを求めればよい。これは結構明らかだと思う(tが最小であるような線分以外を無視すれば重複は解決され、かつ最も覆われる点が多い)。実際に各座標についてやると当然計算量がやばいが、これは簡単なイベント走査で解決できる。線分(l, r, t)についてイベント(l, t)とイベント(r, t)を作成し、イベントの集合を1つ目の要素に関してソート。multisetを1つ使って(l, t)が来たらtをinsert、(r, t)が来たらtをeraseしていけば、連続する2つのイベント(x1, t1), (x2, t2)について、区間[x1, x2]におけるtの最小値は、イベント(x1, t1)を処理し終わった後のmultisetの最小値となる。これも多分典型。なので各イベントの処理後に新しい線分の集合に、それらの値を追加してやれば、重複を取り除いた線分が全て求められて、解ける。このやり方ではどうやっても、重複を取り除いた線分は流石に自明にO(m)個しか存在しないので、かなり適当に追加しても問題ない。

 

ちなみに初め誤読して、「点は線分に覆われなくなったらその場で止まる。」という条件があると思っていたんだけど、それでも解けるので考えてみてください。

Codeforces Round #176 (Div. 1)

codeforces.com

はいサイアクの1完。

Bが分からない時は本当に辛いンゴねえ

 

A. nが与えられる。1~nの順列P[1]~P[n]が「∀i(1 <= i <= n) P[P[i]] = n+1-i」を満たす。このようなPを1つ出力せよ。そのようなPがなければ-1と出力すること。

順列なのでグラフではdirected "cycle"(cyclicではない) graphの集合と対応する。グラフにおいては、上の条件は、頂点iから有向辺を2本辿った先の頂点が常にn+1-iであることを表している。頂点n+1-iから2本辿った先が頂点iにならないといけないから、そのような条件を満たす順列は、大きさ1または4のdirected cycle graphのみで構成されている(ただしnが奇数でかつ頂点(n+1)/2についてのみ大きさ1は許される)。

よって与えられたnをまず4で割って、剰余が2, 3であればそのようなPはない。

後は適当にやればよくて、nが奇数であれば、ans[(n+1)/2] = (n+1)/2にだけ気をつけて、(k)→(k+1)→(n+1-k)→(n-k)→(k)みたいな閉路を考えて答えを構成してやればよい。

なんかめっちゃバグった。アホ。

 

B. 1~nの順列P[1]..P[n]と自然数kをとって、P[2]P[3]...P[k]P[1], P[k+2]P[K+3]...P[2k]P[k+1], ...を新しい順列として返す写像f(P, k)を定義する(つまり順列をk個ごとで区切って、区切った中で先頭の数を最後に移動させる)。L[1] = [1, 2, 3, ..., n]として、L[k] = f(L[k-1], k)と置く。L[n]を求めよ。

まず最後に移動させる操作の回数は、Σ[i=2..N]ceil(N/i) = O(NlogN)であるから、L[1][1] ~ L[n][n]のn^2個の数の内、いい感じに最後に移動させる数だけを処理することが出来れば、つまり1つの区間内のシフトをO(1)で出来ればO(NlogN)が達成できることはわかる。

ここからが問題で、僕はL[n]におけるi番目の数がL[1]においてどこにあったかというのを独立に考えようとしたのでドツボにハマった。つまり、L[1] ~ L[n]を正方形に並んだn^2個の数だというイメージで見た時、僕は縦に区切って処理しようとしてしまったんだけど、横に区切らないといけなかった。横に区切る、つまりL[k]からL[k+1]を一度に求めようという気持ちでいくとちゃんと出来て、これは、最後に移動させられる数を無視してみると、左に1個ずつズレていくだけだから、このズレを実際にはズラさずに固定してやると良い。どういうことかというと、配列L[k]から配列L[k+1]を作る時、本来ならL[k+1][i-1] = L[k][i]とやるわけだけど、定数1分ずつ全てがズレるのだから、i' = i-1と置いてやれば、L[k+1][i'] = L[k][i]と出来て、L[k+1]を新しく生成するのではなく、L[k]をinplaceに置き換えることにすると(dpのメモリ削減みたいなもん)、1ズレる数に関しては値を参照したりコピーする必要がなくなる。後は、最後に移動させる必要のある数だけ、L[k+1][i+k-1] = L[k][i]みたいな感じにする必要があるから、i'とinplaceを考えると、後ろからL[i'+k] = L[i]で更新していくだけでよく、上の評価式からこの更新の回数はO(NlogN)であるから解ける。

 

ちなみにL[n][i]がL[1]においてどこにあるかという考え方だと、O(NlogN(logN+loglogN))は達成できるんだけど、N=10^6でしかも旧版の問題に対する処置としてTLEが1/2の1秒だから普通に間に合わない。

 

自分用メモ: 流石にどっちで対処するかぐらいちょっと考えましょう、というか結構dpの変数置き換えはよくやるし好きなんだからこれぐらい思いつくべき

Codeforces Round #127 (Div. 1)

codeforces.com

f:id:potetisensei:20161024174651p:plain

 

tourist回嫌い(直球)

色々やってしまい1完でした。

 

A. 以下の様な条件を満たす行列を考える。

  • n*nの正方行列である
  • 全ての要素が0または1
  • 行列は上下左右対称すなわちAi, j = An - i + 1, j and Ai, j = Ai, n - j + 1が成り立つ
  • 上下左右に隣り合う要素同士が同時に1となることはない

そのような行列の内、1をx個要素としてもつものを構成することの出来る最小のnを求めよ。

なんか本当にヤバそうだなあと思いながら適当にやったら6WAぐらいして諦めた。

計算量は問題にならないので、n=1から順に試していけば良い。

そして基本的にまずnが偶数か奇数かで場合分けしないといけない。

nが偶数の時は結構簡単で、最後の条件と対称性から、中央の2行2列は0で埋まる。すると小さい正方形4つに分かれるイメージになって、それらの正方形には最後の条件以外を特に考えないで埋める事ができるから、xが4の倍数であってかつx/4 <= MAX_PLACE( (n-2)/2)であればよい。ここでMAX_PLACE(t)はt*tの正方形に最後の条件を満たすように入れることの出来る1の最大数。

nが奇数の時が辛い。nが奇数の時、nが偶数の時と同様に中央の1行1列以外の場所に1が存在する時は、勝手に対称性から4つ発生するので、4の倍数ずつ増える。

中央の1行1列でかつ、完全な中央でない場所に1が存在する時は、対称性から2つ発生するので2の倍数ずつ増える。

完全に中央に1が存在する時は、対称性を考えなくていいので1個だけ増やせる。

その上で、中央が1かそうでないかによって、置くことの出来る数が変わる。

まず、中央が1である時、すなわちxが奇数の時、他の場所に、1は、0 <= a <= MAX_PLACE( (n-1)/2) ∧ 0 <= b <= ( (n-1)/4) * 2を満たす様な(a, b)で表せる4 * a + 2 * b個であれば置くことが出来る。

中央が1でない時、すなわちxが偶数の時、(n-1)/2が奇数の時、中央に1がないことによって、2 * bのbが2増えるため、これを考慮しないと落ちる。分かってたけど実装しなかったのはカス。

もうちょっと良い方法ないのかなあ。

 

B. n, m, Cが与えられるので、Σ[i=1..n]Σ[j=1..m] C[i][j] * D{(4X, 4Y), (4j-2, 4i-2)}^2 を最小化するようなX, Yと最小化された値を求めよ。ただしDはユークリッド距離

なんかユークリッド距離とマンハッタン距離を頭の中で取り違えるやらかしが発生したせいでめちゃくちゃ悩んだ。距離に2乗がついてるから次元が分解出来ないンゴねえって感じ。最終的に、定点に対するマンハッタン距離の関数D(X, Y)は2次元で離散な凸関数になっていて、2乗しても凸のままで、凸関数の和は凸関数だから、結局全体として2次元の凸関数だから3分探索すればエエやんけと思って、O(NM * log3/2(N) * log3/2(M))を書いたらTLEして落ちた(概算が10^9なので当たり前、概算しましょう)。でTLEしてオイオイオイとなった時にユークリッド距離であることに気づく。ユークリッド距離の2乗はX, Yの項が分離するから次元が分解できるンゴねえ....

よって適当に上の目的関数をXとYの項に分解して同じように3分探索すると、logが1つ消えて通った。

 

C. n個の頂点がn-1本の辺によって接続され連結になっていて、このグラフは道である。各辺には人が通れる回数の上限が決まっている。好きな頂点から初めて好きに辺を通って良い時、最大で何回移動することが出来るか。

n-1本の辺の通ることの出来る上限回数を左からE1, E2, ..., En-1とする。

ちょっと考察すると、全体で移動出来る回数は、1 <= a <= b <= c <= d <= n-1を用いて、Σ[i=a..d-1] Ei - |{Ei | Eiが奇数 i=a..b-1)}| - |{Ei | Eiが偶数 i=b..c-1)}| - |{Ei | Eiが奇数 i=c..d)}|と表すことが出来、これの最大を求めれば良いことが分かる。これはどうしてかというと、何度も同じ辺を行き来することが出来るから、とりあえず最大化するためにはi番目の辺を通る時はEi-2回往復してしまうと、残り上限2回をどう通るかによって、行って引き返してきたり、行ったまま帰ってこなかったり、そもそも通らなかったりする(当たり前)。これは何を意味しているかというと、全体の経路はかならず、(1度通って引き返してくる辺たち) (1度通ったきり引き返して来ない辺たち) (1度通って引き返してくる辺たち)という並びになってないとおかしい。要は偶数回通る辺、奇数回通る辺、偶数回通る辺というふうに連続して存在している(もしくはこれらの内存在しない辺の集合があってもいい)。図にするとこんな感じ。まあ自分で書いたら分かると思う。

 

f:id:potetisensei:20161024171543p:plain

後は計算量と、初めから上限回数が1の辺の処理が問題になる。

とりあえず後者は一旦無視して考えると、流石にさっきの上の式の4変数を総当りするとO(n^4)になって間に合わないので、自明な変数を削る所から始める。

まずa, dはなくてもいい。これはa, dは左端と右端に設定した方が絶対に通れる回数が大きくなって得だから。

bは流石にないと困るので、これは総当りすることにする(bの総当りでO(n))。

これによって、固定したbに対して、最大の移動回数を与えるようなcを効率良く求めたいと考えられる。

これは結構簡単で、要は「bit列が与えられる。bit列をある場所で分割して、それより左側にあるbitを全て反転させる。この時、立っているbitの数を最小化するにはどの位置で分割すれば良いか。」という問題と同じ。

これは、左から、

diff[idx] := 位置idxまでに出現した1の数と位置idxまでに出現した0の数の差

を累積和的に計算して、segment treeなどに突っ込んでおけば、Range Max Queryによって、maxidx = argmax(diff[idx])が分かって、位置maxidxで反転させると、立っているbitは最小化されて|{Ei | Eiが奇数 i=b..n-1)}| - (diff[maxidx] - diff[b-1])になることが分かる。ちなみに実際には反転させないケースもあるので、|{Ei | Eiが奇数 i=b..n-1)}| - max(diff[maxidx] - diff[b-1], 0)。

さて問題は上限回数が初めから1回であるような辺が含まれている時で、これがかなり罠。なんか上までの考察はすぐ終わったのに本当に嘘&バグらせで辛い思いをした。

さて、上限回数が1回である辺は、当然2回通ることが出来ないから、aからb-1やcからdに含まれては行けない。よって、最も右に存在する1の場所pつまりEp=1となる最大のpを記憶して(1がなければp = 1)、RMQのクエリの区間の左端をpに設定する必要がある(つまり[p, n-1]にクエリを投げる)。これだけだと、RMQを[0, p-2]に飛ばしていないわけだからpより右側の辺を一切通らないケースを考慮していなくて嘘っぽいけど、ある辺iについてそこを通る回数はEi - {0, 1}でこれは常に0以上であるから、さっきも言った通り全ての道を通ったケースが、全ての道を通らないケースに比べて劣ることは絶対にない。

累積和を取ったりindexをいじったりする系の奴、考察が終わっていてもバグりまくるの辛いしどうにかしてくれ。

 

自分向けメモ: コーナーケースとかヤバそうなケース思いついたらとりあえずメモっとけ。考察もう少し丁寧に。嘘が入らない程度に考察は少しずつ積み重ねる。飛躍出来るだけしない。

 

Codeforces Round #177 (Div. 1)

codeforces.com

 

受験終わって初回virtual。3完。辛い。

 

A. k種類の小文字アルファベットから成るちょうど長さnの文字列であって、隣り合う文字が全て異なるものの内、辞書順最小のものは何か。

流石にaから始まるのが辞書順最小で、次は隣り合う文字は異なってないといけないからbで、次はaでと考えると、ababab...となる。後は末尾にk-2種類の文字、それも辞書順最小なので当然'c' ~ 'c'+k-3を登場させると良いけど、ちょっと実装がだるい。k=1とかに気をつける

 

B. σはS={1,..., n}のS→Sな写像であって、「∀t(1 <= t <= k)について∃x(x∈N)が存在して、σ^x(t)=1」∧「∀t(k < t <= n)についてσ^x(t)=1を満たすxが存在しない」を満たす。σは何通りあるか。

こういった写像はdirected pseudoforestと対応するので、自明に1個のdirected pseudotreeと、{k+1, .. , n}→{k+1, .., n]の任意の写像1つの数え上げ。後者は自明に(n-k)^(n-k)。いちおうdirected pseudotreeと書いたけど、実はこの場合は有向辺と無向辺が一対一に対応して数え上げられるので、pseudotreeでいいはず。なんかpseudotreeといえば、閉路の各頂点に、0個以上の木がくっついてる形をしているわけだけれども、道しかくっついていないという嘘想定を何故かしてしまって死んだ。この良く分からん勘違い、春合宿でもやってしまったけどマジで意味が分からん。

結局やることとしては、σ^x(1)=1となるxが存在するわけだから、pseudotreeの閉路上に頂点1は存在する。後は、どうにでも出来ると思うけど、例えば閉路がt個の頂点から構成されるとすると、閉路上にある頂点は残りt-1個に関しては自由なので(n-1)C(t-1)通り。そしてt-1個の並びは自由なので(t-1)!通り。

後は木をこの閉路につけるわけだけど、ここで、一般に、無向グラフにおいて、十分に大きいnについて、n個の互いに非連結な成分C1 ~ Cnをn-1本の辺で連結にする時、異なる連結のさせ方は(π[i=1..n]Ci) × {(Σ[1..n] |Ci|)^(n-2)}通りある。これは∀iで|Ci|=1のとき、cayleyの公式と一致する。

以上から答えは、(n-k)^(n-k) × [Σ[t=1..k-1]{(t-1)! × (k-1)C(t-1) × t × k^(t-k-1)} + (k-1)!] となる(t == kのとき、t-k-1 = -1なことに注意する)。

 

C. 0~nの順列P0~Pnについて美しさを Σ[i=0..n] (i⊕Pi)で定義する(⊕はXOR)。可能な美しさの最大値と最大値を与える順列1つを出力せよ。

等式 A⊕B = A+B - ((A&B) << 1)を用いると(ここで&はAND)、Σ[i=0..n] (i⊕Pi) ≦ Σ(i+Pi) = n(n+1)であって、上界がn(n+1)であることが分かる。

貪欲に順列を構成すると、上界を達成することが出来ることを示す。

まず

  • 2進数でnがk桁で表されるとすると、k桁で表される全ての整数tについて、t⊕x = 2^k-1となるようなxがただ1つ存在する。これはt&x = 0となるようなxがk-1桁以下で表される整数にただ1つ存在することによる。
  • t1⊕x1 = 2^k-1, t2⊕x2 = 2^k-1の時、t1≠t2 ⇒ x1≠x2である
  • 上記の条件でt⊕x = 2^k-1となる時、A&B = 0 ⇔ A+B = A⊕Bを考えるとt+x = t⊕x = 2^k-1である。

ここで、n以下でかつk桁で表される全ての整数の集合、すなわち、”離散な"閉区間(面倒くさいのでこう呼ぶ)S = [2^(k-1), n]に対して、T = {x | t∈S, t⊕x = 2^k-1}とすれば、t+x = t⊕xより、Tは離散な閉区間[2^k-1-n, 2^(k-1)-1]であり、S∩T=∅かつS∪T = [2^k-n-1,  n]であるから、これらを全て消費すると、離散な閉区間[0, 2^k-n-2]が残るので、残った離散な閉区間に対して、同じ問題を再帰的に解いていくと良い。

こうして構成された順列は、全ての項について、i⊕Pi = i+Piが成り立っているので、上の考察からこれは上界を与えている。

なんか実装力が衰えすぎていたのと、この考察中々にややこしいのでめちゃくちゃなバグが発生しまくった。反省。

 

自分向けメモ: 貪欲の下界上界を先に意識するパターン忘れない。一回やったら流石にcombinatoricsは解けて...

四則演算するテスト

前書いたスタックを使って

前々から気になってた逆ポーランド記法に変換して処理する四則演算器書いた。

 

infix2postfix.h

#include <stdio.h>
#include <stdlib.h>
#include "stack.h"

enum Priority {NIL, LOW, MIDDLE, HIGH,};

static void check_argument(char **string, stack *st)
{
    make_stack(for_string);
    char *tmp;
    tmp = (char *)malloc(sizeof(char));
    if(tmp == NULL){
        break_stack(*st);
        return;
    }
    *tmp = ' ';
    push_stack(st, tmp);
    while(1){
        tmp = (char *)malloc(sizeof(char));
        if(tmp == NULL){
            break_stack(*st);
            return;
        }
        if(**string == '.' || **string == '_' || **string == '@' || ('A' <= **string && **string <= 'Z') || ('a' <= **string && **string <= 'z')){
            *tmp = **string;
            push_stack(&for_string, tmp);
            ++(*string);
        }else if(**string == '('){

        }else{
            while(top_stack(&for_string) != NULL){
                push_stack(st,top_stack(&for_string));
                pop_stack(&for_string);
            }
            --(*string);
            return;
        }

    }
}

static int check_constant(char **string, stack *st)
{
    make_stack(for_string);
    char *tmp;
    tmp = (char *)malloc(sizeof(char));
    if(tmp == NULL){
        break_stack(*st);
        return;
    }
    *tmp = ' ';
    push_stack(st, tmp);
    while(1){
        tmp = (char *)malloc(sizeof(char));
        if(tmp == NULL){
            break_stack(*st);
            return;
        }
        if('0' <= **string && **string <= '9'){
            *tmp = **string;
            push_stack(&for_string, tmp);
            ++(*string);
        }else{
            while(top_stack(&for_string) != NULL){
                push_stack(st,top_stack(&for_string));
                pop_stack(&for_string);
            }
            --(*string);
            return;
        }
    }
}  
   
static int ret_prio(char str)
{
    enum Priority;
    if(str == '(' || str == ')')return NIL;
    if(str == '+' || str == '-')return LOW;
    if(str == '*' || str == '/' || str == '%')return MIDDLE;
    if( ('a' <= str && str <= 'z') || ('A' <= str &&  str <= 'Z') || str == ' ' || str == '_' || str == '@' || str == '.' || ('0' <= str && str <= '9'))return HIGH;
    return -1;
}

char *convert(char *formula,char for_convert[])
{
    int i = 0;
    make_stack(st);
    while(*formula != '\0'){
        char *tmp;
        while(*formula == ' ') ++formula;
        if(*formula == '('){
            tmp = (char *)malloc(sizeof(char));
            *tmp = *formula;
            push_stack(&st, (void *)tmp);
        }else if(*formula == ')'){
            while(*(char *)top_stack(&st) != '('){
                if(top_stack(&st) != NULL){
                    *(for_convert+i) = *(char*)top_stack(&st);
                    ++i;
                    free(top_stack(&st));
                    pop_stack(&st);
                }else{
                    puts("error");
                    break_stack(st);
                    return NULL;
                }

            }
            pop_stack(&st);
        }else if( ('a' <= *formula && *formula <= 'z') || ('A' <= *formula && *formula <= 'Z') || *formula == '_' || *formula == '@' || *formula == '.'){
            check_argument(&formula, &st);
        }else if('0' <= *formula && *formula <= '9'){
            check_constant(&formula, &st);
        }else if(*formula == '+' || *formula == '-' || *formula == '*' || *formula == '/' || *formula == '%'){
            while(top_stack(&st) != NULL && ret_prio(*formula) <= ret_prio(*(char *)top_stack(&st))){
                *(for_convert+i) = *(char*)top_stack(&st);
                ++i;
                free(top_stack(&st));
                pop_stack(&st);
            }
            tmp = (char *)malloc(sizeof(char));
            if(tmp == NULL){
                break_stack(st);
                return NULL;
            }
            *tmp = ' ';
            push_stack(&st, (void *)tmp);
            tmp = (char *)malloc(sizeof(char));
            if(tmp == NULL){
                break_stack(st);
                return NULL;
            }
            *tmp = *formula;
            push_stack(&st, (void *)tmp);
        }else{
            break_stack(st);
            return NULL;
        }
        ++formula;
    }
    while(top_stack(&st) != NULL){
        if(*(char*)top_stack(&st) == '('){
            int m;
            puts("error");
            break_stack(st);
            for(m=0;m!=i;++m){
                *(for_convert+m)='\0';
            }
            return NULL;
        }
        *(for_convert+i) = *(char*)top_stack(&st);
        ++i;
        free(top_stack(&st));
        pop_stack(&st);
    }
    break_stack(st);
    return 0;
}

 

eval4rules.h

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <setjmp.h>
#include "stack.h"

double evaluation(char *formula,jmp_buf for_error){
    make_stack(st);
    double Ret;
    char p[20]="";
    while(*formula != '\0'){
        const char *var_for_atoi;
        if('0' <= *formula && *formula <= '9'){
            double *num = (double*)malloc(sizeof(double));
            if(num == NULL){
                break_stack(st);
                longjmp(for_error,-2);
            }
            while('0' <= *formula && *formula <= '9'){
                char chr[2] = "";
        chr[0] = *formula;
                strcat(p,chr);
                ++formula;
            }
            var_for_atoi = p;
            *num = atof(var_for_atoi);
            push_stack(&st,num);
            strcpy(p,"");
        }else if(*formula == '+' || *formula == '-' || *formula == '*' || *formula == '/'){
            double *num = (double*)malloc(sizeof(double));
            if(num == NULL){
                break_stack(st);
                longjmp(for_error,-2);
            }
            double a,b;
            if(top_stack(&st) == NULL){
                break_stack(st);
                longjmp(for_error,-1);
            }else{
                a = *(double*)top_stack(&st);
                free(top_stack(&st));
                pop_stack(&st);
            }
            if(top_stack(&st) == NULL){
                break_stack(st);
                longjmp(for_error,-1);
            }else{
                b = *(double*)top_stack(&st);
                free(top_stack(&st));
                pop_stack(&st);
            }
            switch(*formula){
            case '+':
                *num = a+b;
                break;

            case '-':
                *num = b-a;
                break;

            case '*':
                *num = a*b;
                break;

            case '/':
                *num = b/a;
                break;
            }
            push_stack(&st,num);
            ++formula;
        }else if(*formula != ' '){
            break_stack(st);
            longjmp(for_error,-1);
        }
        ++formula;
    }
    if(top_stack(&st) == NULL){
        break_stack(st);
        longjmp(for_error,-1);
    }
    Ret = *(double*)top_stack(&st);
    free(top_stack(&st));
    pop_stack(&st);
    break_stack(st);
    return Ret;
}

 

 

main.c

#include <stdio.h>
#include <setjmp.h>
#include "infix2postfix.h"
#include "eval4rules.h"

int main()
{  
    int i;
    double n;
    char formula[300];
    char Result[10000] = "";
    jmp_buf env;
    i = setjmp(env);
    if(i == 0){
        scanf("%s",formula);
        convert(formula,Result);
        n = evaluation(Result,env);
        printf("n:%f\n",n);
        return 0;
    }else if(i == -1){
        puts("SyntaxError");
        return -1;
    }else if(i == -2){
        puts("Stack memory limits");
        return -1;
    }
}

 

テストなので字句解析とかすっ飛ばしてるけど今ちゃんと書いてるので。

あと、エラー処理適当かなと。