結果

問題 No.708 (+ー)の式
ユーザー AreTrashAreTrash
提出日時 2019-04-28 02:41:44
言語 C#(csc)
(csc 3.9.0)
結果
AC  
実行時間 64 ms / 2,000 ms
コード長 8,749 bytes
コンパイル時間 4,882 ms
コンパイル使用メモリ 109,080 KB
実行使用メモリ 17,692 KB
最終ジャッジ日時 2023-08-20 12:21:55
合計ジャッジ時間 6,245 ms
ジャッジサーバーID
(参考情報)
judge12 / judge14
このコードへのチャレンジ(β)

テストケース

テストケース表示
入力 結果 実行時間
実行使用メモリ
testcase_00 AC 62 ms
17,432 KB
testcase_01 AC 61 ms
17,484 KB
testcase_02 AC 60 ms
17,444 KB
testcase_03 AC 61 ms
17,692 KB
testcase_04 AC 58 ms
15,608 KB
testcase_05 AC 58 ms
15,548 KB
testcase_06 AC 62 ms
17,440 KB
testcase_07 AC 63 ms
17,596 KB
testcase_08 AC 64 ms
17,448 KB
testcase_09 AC 63 ms
17,588 KB
testcase_10 AC 63 ms
17,480 KB
testcase_11 AC 62 ms
17,572 KB
testcase_12 AC 62 ms
17,576 KB
testcase_13 AC 60 ms
15,684 KB
testcase_14 AC 58 ms
15,608 KB
権限があれば一括ダウンロードができます
コンパイルメッセージ
Microsoft (R) Visual C# Compiler version 3.9.0-6.21124.20 (db94f4cc)
Copyright (C) Microsoft Corporation. All rights reserved.

ソースコード

diff #

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace No708
{
    public class Program
    {
        static void Main(string[] args)
        {
            var syntax = new Syntax(Console.ReadLine());
            var expression = new Expression();
            expression.Parse(syntax);
            var res = expression.Calc();
            Console.WriteLine(res);
        }
    }

    public class Syntax
    {
        readonly string expression;

        int prev = -1;
        int index = 0;

        public char Previous => prev < 0 ? '\0' : expression[prev];
        public char Current => index >= expression.Length ? '\0' : expression[index];

        public Syntax(string expression)
        {
            this.expression = expression;
        }

        public void Next()
        {
            prev = index;
            do index++;
            while (Current == ' ');
        }
    }

    public abstract class Node
    {
        Syntax syntax;
        readonly List<Node> nodes = new List<Node>();

        protected IReadOnlyList<Node> Nodes => nodes;

        protected void Add(Node node)
        {
            node.Parse(syntax);
            nodes.Add(node);
        }

        protected abstract void ParseCore(Syntax syntax);

        // ReSharper disable once ParameterHidesMember
        public void Parse(Syntax syntax)
        {
            nodes.Clear();
            ParseCore(this.syntax = syntax);
        }

        public abstract double Calc();
    }

    public class Letter : Node
    {
        string letter;

        protected override void ParseCore(Syntax syntax)
        {
            letter = syntax.Current.ToString();
            syntax.Next();
        }

        public override double Calc()
        {
            throw new Exception("LetterNodeは計算できません");
        }

        public override string ToString()
        {
            return letter;
        }
    }

    public class Number : Node
    {
        //<number> ::= ('0'-'9') {'0'-'9'} ['.'{'0'-'9'}]
        protected override void ParseCore(Syntax syntax)
        {
            var dots = 0;
            if (!char.IsDigit(syntax.Current)) throw new Exception("NumberNodeは数字から始まる必要があります");
            while (char.IsDigit(syntax.Current) || (syntax.Current == '.' && ++dots <= 1)) Add(new Letter());
        }

        public override double Calc()
        {
            return double.Parse(ToString());
        }

        public override string ToString()
        {
            return string.Join("", Nodes);
        }
    }

    public class Bracket : Node
    {
        //<bracket> ::= '(' <expression> ')'
        protected override void ParseCore(Syntax syntax)
        {
            if (syntax.Current != '(') throw new Exception("BracketNodeは丸かっこから始まる必要があります");
            Add(new Letter());
            Add(new Expression());
            if (syntax.Current != ')') throw new Exception("BracketNodeは丸かっこで終了する必要があります");
            Add(new Letter());
        }

        public override double Calc()
        {
            return Nodes[1].Calc();
        }

        public override string ToString()
        {
            return string.Join("", Nodes);
        }
    }

    public class Factor : Node
    {
        bool isNegative = false;

        //<factor> ::= (<number>|<bracket>)
        protected override void ParseCore(Syntax syntax)
        {
            if (syntax.Current == '-')
            {
                if (syntax.Previous != '\0' && syntax.Previous != '(') throw new Exception("不正な位置にマイナス記号が存在します");
                isNegative = true;
                Add(new Letter());
            }

            if (char.IsDigit(syntax.Current)) Add(new Number());
            else if (syntax.Current == '(') Add(new Bracket());
            else throw new Exception("FactorNode で NumberNode もしくは BracketNode に該当しそうなものがありません");
        }

        public override double Calc()
        {
            return (isNegative ? -1 : 1) * Nodes.Last().Calc();
        }

        public override string ToString()
        {
            return string.Join("", Nodes);
        }
    }

    public class SquareRoot : Node
    {
        //<root> ::= {'r'} <factor>
        protected override void ParseCore(Syntax syntax)
        {
            while (syntax.Current == 'r') Add(new Letter());
            Add(new Factor());
        }

        public override double Calc()
        {
            var x = Nodes.Last().Calc();
            if (Nodes.Count == 1) return x;
            if (x < 0) throw new Exception("負数の平方根には対応してません");
            for (var i = 0; i < Nodes.Count - 1; i++) x = Math.Sqrt(x);
            return x;
        }

        public override string ToString()
        {
            return string.Join("", Nodes);
        }
    }

    public class Factorial : Node
    {
        //<factorial> ::= <square_root> {'!'}
        protected override void ParseCore(Syntax syntax)
        {
            Add(new SquareRoot());
            while (syntax.Current == '!') Add(new Letter());
        }

        public override double Calc()
        {
            var d = Nodes.First().Calc();
            var x = (int)Math.Round(d);

            if (Nodes.Count == 1) return d;
            if (Math.Abs(d - x) > double.Epsilon || x < 0) throw new Exception("階乗を計算できるのは0以上の整数のみです");
            if (x == 0) return 1;

            for (var i = 0; i < Nodes.Count - 1; i++)
            {
                for (var y = x - 1; y >= 2; y--) x *= y;
            }

            return x;
        }

        public override string ToString()
        {
            return string.Join("", Nodes);
        }
    }

    public class Power : Node
    {
        //<power> ::= <factorial> {'^' <factorial>}
        protected override void ParseCore(Syntax syntax)
        {
            Add(new Factorial());
            while (syntax.Current == '^')
            {
                Add(new Letter());
                Add(new Factorial());
            }
        }

        public override double Calc()
        {
            var x = Nodes[0].Calc();
            for (var i = 2; i < Nodes.Count; i += 2)
            {
                var y = Nodes[i].Calc();
                x = Math.Pow(x, y);
            }
            return x;
        }

        public override string ToString()
        {
            return string.Join(" ", Nodes);
        }
    }

    public class MulDiv : Node
    {
        //<mul_div> ::= <power> {('*'|'/') <power>}
        protected override void ParseCore(Syntax syntax)
        {
            Add(new Power());
            while (syntax.Current == '*' || syntax.Current == '/')
            {
                Add(new Letter());
                Add(new Power());
            }
        }

        public override double Calc()
        {
            var x = Nodes[0].Calc();
            for (var i = 2; i < Nodes.Count; i += 2)
            {
                var op = Nodes[i - 1].ToString();
                var y = Nodes[i].Calc();
                if (op == "*") x *= y;
                if (op == "/") x /= y;
            }
            return x;
        }

        public override string ToString()
        {
            return string.Join(" ", Nodes);
        }
    }

    public class AddSub : Node
    {
        //<add_sub> ::= <mul_div> {('+'|'-') <mul_div>}
        protected override void ParseCore(Syntax syntax)
        {
            Add(new MulDiv());
            while (syntax.Current == '+' || syntax.Current == '-')
            {
                Add(new Letter());
                Add(new MulDiv());
            }
        }

        public override double Calc()
        {
            var x = Nodes[0].Calc();
            for (var i = 2; i < Nodes.Count; i += 2)
            {
                var op = Nodes[i - 1].ToString();
                var y = Nodes[i].Calc();
                if (op == "+") x += y;
                if (op == "-") x -= y;
            }
            return x;
        }

        public override string ToString()
        {
            return string.Join(" ", Nodes);
        }
    }

    public class Expression : Node
    {
        //<expression> ::= <add_sub>
        protected override void ParseCore(Syntax syntax)
        {
            Add(new AddSub());
        }

        public override double Calc()
        {
            return Nodes.Last().Calc();
        }

        public override string ToString()
        {
            return string.Join("", Nodes);
        }
    }
}
0