简体   繁体   English

你能简化这个算法吗?

[英]Can you simplify this algorithm?

One for the mathematicians. 一个是数学家。 This has gone around the office and we want to see who can come up with a better optimised version. 这已经遍布办公室,我们希望看到谁能想出更好的优化版本。

(((a+p) <= b) && (a == 0 || a > 1) && (b >= p)) && 
    ((b - (a + p) == 0) || (b - (a + p) > 1))

Edit : all data is positive int's 编辑 :所有数据都是正整数

Edit : Better == refactored for simplicity 编辑 :更好==为简单而重构

(a + p <= b) && (a != 1) && (b - a - p != 1);

If the formula works and come from your business rules there is no real need to simplify it. 如果公式有效且来自您的业务规则,则无需简化它。 The compiler probably knows better than us how to optimizing the formula. 编译器可能比我们更了解如何优化公式。

The only thing you should do is use better variables names which reflect the business logic. 您应该做的唯一事情是使用反映业务逻辑的更好的变量名称。

Beware of applying any of the proposed solution before unit testing them. 在进行单元测试之前,请注意应用任何建议的解决方案。

Refactor for simplicity by introducing more local variables which indicate the meaning of each expression. 通过引入更多指示每个表达式含义的局部变量来简化重构。 This is hard for us to do with no idea of what a, b and p mean. 这对我们来说很难做到,不知道a,b和p是什么意思。

b >= p && b != p+1

编辑:好的,这不起作用,但这个做:

a != 1 && b >= a+p && b-a-p != 1
(a!=1) && ((b==a+p) || (b>1+a+p))

它可能不是最简单的,但应该是最可读的。

I wouldnt do all math in that expression. 我不会在那个表达式中做所有的数学运算。 Such as b - ( a + p ) is evaluated twice. 例如b - (a + p)被评估两次。 If possible, split them into variables instead. 如果可能,请将它们拆分为变量。

Also, writing a polish notiation tree might help you optimize it, everything that you see twice, can be re-used. 此外,编写一个抛光公差树可能会帮助您优化它,您可以重复使用两次看到的所有内容。

Since they are all positive ints a lot of the repetition can be removed: 由于它们都是正面的,所以可以删除很多重复:

So as a first step, 所以作为第一步,

(((a+p) <= b) && (a == 0 || a > 1) && (b >= p)) && ((b - (a + p) == 0) || (b - (a + p) > 1))

becomes

((a+p) <= b) && (a != 1) && (b >= p)) && ((b - (a + p) != 1) 

For clarity, this is just replacing the (foo == 0 || foo > 1) pattern with foo != 1 为清楚起见,这只是用foo != 1替换(foo == 0 || foo > 1)模式

That pattern appears twice above, once with foo = a, and once with foo = (b - (a+p)) 该模式在上面出现两次,一次是foo = a,一次是foo = (b - (a+p))

Since the ints are unsigned, (a==0 || a>1) can be substituted for (a !=1). 由于整数是无符号的,(a == 0 || a> 1)可以代替(a!= 1)。

With a first pass, you can reduce it to this: 通过第一次通过,您可以将其减少到:

uint sum = a + p;
return ((sum <= b) && (a != 1) && (b >= p)) && (b - sum != 1);

Also, it would be much more readable if you were able to give more meaningful names to the variables. 此外,如果您能够为变量提供更有意义的名称,它将更具可读性。 For instance, if a and p were pressures, then a+p could be substitued as PressureSum. 例如,如果a和p是压力,则a + p可以替换为PressureSum。

bap = b - (a + p)
bap >= 0 && bap != 1 && a != 1

EDIT: Now I've got -2 for an honest attempt at helping out and also for what seems to me to be a valid answer. 编辑:现在我已经-2了一个诚实的尝试帮助,也似乎是一个有效的答案。 For you who can use Python, here are two functions, one with the question and one with my answer: 对于可以使用Python的人来说,这里有两个函数,一个是问题,另一个是我的答案:

def question(a, b, p):
    return (((a+p) <= b) and (a == 0 or a > 1) and (b >= p)) or ((b - (a + p) == 0) or (b - (a + p) > 1))

def answer(a, b, p):
    bap = b - (a + p)
    return bap >= 0 and bap != 1 and a != 1
s = a + p
b >= s && a != 1 && b - s - 1 > 0

Checked, returns the same boolean value as the question. 选中,返回与问题相同的布尔值。

Program that I have used to check: (had fun writing it) 我用来检查的程序:(写得很开心)

#include <iostream>
using namespace std;

typedef unsigned int uint;

bool condition(uint a, uint b, uint p)
{
        uint s = a + p;
        return uint(    b >= s && a != 1 && b - s - 1 > 0    )
        == uint(    (((a+p) <= b) && (a == 0 || a > 1) && (b >= p))
                 && ((b - (a + p) == 0) || (b - (a + p) > 1))    );
}

void main()
{
    uint i = 0;
    uint j = 0;
    uint k = 0;

    const uint max = 50;

    for (uint i = 0; i <= max; ++i)
        for (uint j = 0; j <= max; ++j)
            for (uint k = 0; k <= max; ++k)
                if (condition(i, j, k) == false)
                {
                    cout << "Fails on a = " << i << ", b = " << j;
                    cout << ", p = " << k << endl;

                    int wait = 0;
                    cin >> wait;
                }
}

This is as simple as I could get it. 这很简单,我可以得到它。

def calc(a, b, p):
    if (a != 1):
        temp = a - b + p
        if temp == 0 or temp < -1:
            return True
    return False

It could also be written as: 它也可以写成:

def calc(a, b, p):
    temp = a - b + p
    return a != 1 and (temp == 0 or temp < -1)

Or as: 或者:

def calc(a, b, p):
    temp = a - b + p
    return a != 1 and temp <= 0 and temp != -1

Tested with a,b,p from 0 to 10000: 用a,b,p从0到10000进行测试:

a != 1 && a != (b-p-1) && a <= (b-p);

I think it can be simplified even more. 我认为它可以简化得更多。

my apologies for the mistake in the original derivation. 我为原始推导中的错误道歉。 This is what happens when you don't bother to unit test after refactoring! 这是重构后你不打扰单元测试时会发生的事情!

the corrected derivation follows, in the form of a test program. 校正的推导如下,以测试程序的形式。

The short answer is: 简短的回答是:

((a > 1) && (skeet == 0)) || ((a > 1) && (jon > 0) && (skeet < -1));

where 哪里

jon = (b - p)
skeet = (a - jon);

class Program
{
    static void Main(string[] args)
    {
        bool ok = true;
        for (int a = 1; a < 100; a++)
        {
            Console.Write(a.ToString());
            Console.Write("...");

            for (int b = 1; b < 100; b++)
            {
                for (int p = 1; p < 100; p++)
                {
                    bool[] results = testFunctions(a, b, p);
                    if (!allSame(results))
                    {
                        Console.WriteLine(string.Format(
                            "Fails for {0},{1},{2}", a, b, p));
                        for (int i = 1; i <= results.Length; i++)
                        {
                            Console.WriteLine(i.ToString() + ": " + 
                                results[i-1].ToString());
                        }

                        ok = false;
                        break;
                    }
                }
                if (!ok) { break; }
            }
            if (!ok) { break; }
        }
        if (ok) { Console.WriteLine("Success"); }
        else { Console.WriteLine("Failed!"); }
        Console.ReadKey();
    }

    public static bool allSame(bool[] vals)
    {
        bool firstValue = vals[0];
        for (int i = 1; i < vals.Length; i++)
        {
            if (vals[i] != firstValue)
            {
                return false;
            }
        }
        return true;
    }

    public static bool[] testFunctions(int a, int b, int p)
    {
        bool [] results = new bool[16];

        //given: all values are positive integers
        if (a<=0 || b<=0 || p<=0)
        {
            throw new Exception("All inputs must be positive integers!");
        }

        //[1] original expression
        results[0] = (((a+p) <= b) && (a == 0 || a > 1) && (b >= p)) && 
            ((b - (a + p) == 0) || (b - (a + p) > 1));

        //[2] a==0 cannot be true since a is a positive integer
        results[1] = (((a+p) <= b) && (a > 1) && (b >= p)) && 
            ((b - (a + p) == 0) || (b - (a + p) > 1));

        //[3] rewrite (b >= p) && ((a+p) <= b) 
        results[2] = (b >= p) && (b >= (a+p)) && (a > 1) && 
            ((b - (a + p) == 0) || (b - (a + p) > 1));

        //[4] since a is positive, (b>=p) guarantees (b>=(p+a)) so we 
        //can drop the latter term
        results[3] = (b >= p) && (a > 1) && 
            ((b - (a + p) == 0) || (b - (a + p) > 1));

        //[5] separate the two cases b>=p and b=p
        results[4] = ((b==p) && (a > 1) && ((b - (a + p) == 0) || 
            (b - (a + p) > 1))) || ((b > p) && (a > 1) && 
            ((b - (a + p) == 0) || (b - (a + p) > 1)));

        //[6] rewrite the first case to eliminate p (since b=p 
        //in that case)
        results[5] = ((b==p) && (a > 1) && ((-a == 0) || 
            (-a > 1))) || ((b > p) && (a > 1) && 
            (((b - a - p) == 0) || ((b - a - p) > 1)));

        //[7] since a>0, neither (-a=0) nor (-a>1) can be true, 
        //so the case when b=p is always false
        results[6] = (b > p) && (a > 1) && (((b - a - p) == 0) || 
            ((b - a - p) > 1));

        //[8] rewrite (b>p) as ((b-p)>0) and reorder the subtractions
        results[7] = ((b - p) > 0) && (a > 1) && (((b - p - a) == 0) || 
            ((b - p - a) > 1));

        //[9] define (b - p) as N temporarily
        int N = (b - p);
        results[8] = (N > 0) && (a > 1) && (((N - a) == 0) || ((N - a) > 1));

        //[10] rewrite the disjunction to isolate a
        results[9] = (N > 0) && (a > 1) && ((a == N) || (a < (N - 1)));

        //[11] expand the disjunction
        results[10] = ((N > 0) && (a > 1) && (a == N)) ||
            ((N > 0) && (a > 1) && (a < (N - 1)));

        //[12] since (a = N) in the first subexpression we can simplify to
        results[11] = ((a == N) && (a > 1)) || 
            ((N > 0) && (a > 1) && (a < (N - 1)));

        //[13] extract common term (a > 1) and replace N with (b - p)
        results[12] = (a > 1) && ((a == (b - p)) || 
            (((b - p) > 0) && (a < (b - p - 1))));

        //[14] extract common term (a > 1) and replace N with (b - p)
        results[13] = (a > 1) && (((a - b + p) == 0) || 
            (((b - p) > 0) && ((a - b + p) < -1)));

        //[15] replace redundant subterms with intermediate 
        //variables (to make Jon Skeet happy)
        int jon = (b - p);
        int skeet = (a - jon);   //(a - b + p) = (a - (b - p))
        results[14] = (a > 1) && ((skeet == 0) || 
            ((jon > 0) && (skeet < -1)));

        //[16] rewrite in disjunctive normal form
        results[15] = ((a > 1) && (skeet == 0)) || 
            ((a > 1) && (jon > 0) && (skeet < -1));

        return results;
    }
}
// In one line:
return (a != 1) && ((b-a-p == 0) || (b-a-p > 1))

// Expanded for the compiler:
if(a == 1)
    return false;

int bap = b - a - p;

return (bap == 0) || (bap > 1);

If you post the processor you are using, I can optimize for assembly. 如果您发布正在使用的处理器,我可以优化组装。 =] =]

jjngy up here has it right. jjngy在这里是对的。 Here's a proof that his simplified formula is equivalent to the original using the Coq Proof Assistant . 这是一个证明,他的简化公式与使用Coq Proof Assistant的原始公式相同。

Require Import Arith.
Require Import Omega.

Lemma eq : forall (a b p:nat),
(((a+p) <= b) /\ ((a = 0) \/ (a > 1)) /\ (b >= p)) /\ 
    ((b - (a + p) = 0) \/ (b - (a + p) > 1)) <-> 
((a + p <= b) /\ ~ (a= 1) /\ ~ (b - a - p = 1)).
Proof. intros; omega. Qed.

Well

((b - (a + p) == 0) || (b - (a + p) > 1))

Would be better writen as:
(b - (a + p) >= 0)  

Applying this to the whole string you get:

((a+p) <= b) && (a > 1) && (b >= p)) && (b - (a + p) >= 0) 


(a + p) <= b is the same thing as b - (a + p) >= 0

So you can get rid of that leaving: 所以你可以摆脱那个离开:

((a+p) <= b) && (a > 1) && (b >= p)) 

First iteration: 第一次迭代:

bool bool1 = ((a+p) <= b) && (a == 0 || a > 1) && (b >= p);
bool bool2 = (b - (a + p) == 0) || (b - (a + p) > 1);

return bool1 && bool2;

Second iteration: 第二次迭代:

int value1 = b - (a + p);
bool bool1 = (value1 >= 0) && (a == 0 || a > 1) && (b >= p);
bool bool2 = (value1 == 0) || (value1 > 1);

return bool1 && bool2;

Third iteration (all positives) 第三次迭代(所有积极因素)

int value1 = b - (a + p);
bool bool1 = (value1 >= 0) && (a != 1) && (b >= p);
bool bool2 = (value1 == 0) || (value1 > 1);

return bool1 && bool2;

4th iteration (all positives) 第4次迭代(所有正面)

int value2 = b - p;
int value1 = value2 - a;
bool bool1 = (value1 >= 0) && (a != 1) && (b - p >= 0);
bool bool2 = (value1 == 0) || (value1 > 1);

return bool1 && bool2;

5th iteration: 第五次迭代:

int value2 = b - p;
int value1 = value2 - a;
bool bool1 = (value1 >= 0) && (a != 1) && (value2 >= 0);
bool bool2 = (value1 == 0) || (value1 > 1);

return bool1 && bool2;

Alright, I'm hoping that I did my math right here, but if I'm right, then this simplifies quite a bit. 好吧,我希望我在这里做数学,但如果我是对的,那么这简化了很多。 Granted it doesn't look the same in the end, but the core logic should be the same. 虽然它最终看起来不一样,但核心逻辑应该是相同的。

// Initial equation
(((a + p) <= b) && (a == 0 || a > 1) && (b >= p)) && ((b - (a + p) == 0) || (b - (a + p) > 1))

// ((a + p) <= b) iif a = 0 && p = b; therefore, b = p and a = 0 for this to work
(b == p) && ((b - (a + p) == 0) || (b - (a + p) > 1))

// Simplification, assuming that b = p and a = 0
(b == p) && (a == 0)

However, if we are operating under the assumption that zero is neither positive or negative then that implies that any value for a provided to the equation is going to be greater than or equal to one. 但是,如果我们假设零既不是正数也不是负数,那么这意味着提供给方程的任何值都将大于或等于1。 This in turn means that the equation will always evaluate to false due to the fact that the following: 这反过来意味着由于以下事实,等式总是会评估为假:

(a == 0 || a > 1)

Would only evaluate to true when a >= 2; 只有当> = 2时才会评估为真; however, if the following is also true: 但是,如果以下情况也是如此:

(b >= p)

Then that means that p is at least equal to b, thus: 那意味着p至少等于b,因此:

((a + p) <= b)

By substitution becomes: 通过替换成为:

((2 + b) <= b)

Which can clearly never evaluate to true. 这显然永远不会评估为真。

I added this as a comment to nickf's answer but thought I'd offer it up as an answer on it's own. 我添加了这个作为对nickf答案的评论,但我认为我会提供它作为答案。 The good answers all seem to be a variation of his, including mine. 好的答案似乎都是他的变种,包括我的。 But since we're not depending on the compiler for optimization (if the OP were, we wouldn't even be doing this) then boiling this down from 3 ANDs to the following means that there will be values where only 2 of the 3 portions will need to be evaluated. 但是因为我们不依赖于编译器来进行优化(如果OP是,我们甚至不会这样做)然后将其从3个AND分析到下面意味着将存在这样的值,其中3个部分中只有2个需要进行评估。 And if this is being done in a script, it would make a difference as opposed to compiled code. 如果这是在脚本中完成的,那么与编译代码相反,它会产生影响。

(a != 1) && ((b > (a + p + 1)) || (b == (a + p))))

Based on a comment, I'm going to add this wrt this being better than the AND version: 基于评论,我将添加此wrt这比AND版本更好:

I guess it depends on whether your true results data set is larger than 50 percent of the input sets. 我想这取决于您的真实结果数据集是否大于输入集的50%。 The more often the input is true, the better my variation will be. 输入越真实,我的变化就越好。 So, with this equation, it looks like the AND style will be better (at least for my input data set of 0-500). 因此,使用此等式,看起来AND样式会更好(至少对于我的输入数据集0-500)。

If a, b and p are positive integers (assuming that the positive range include the 0 value) then the expression (((a+p) <= b) && (a == 0 || a > 1) && (b >= p)) && ((b - (a + p) == 0) || (b - (a + p) > 1)) can be reduced to ((a+p)<=b) && (a!=1) && ((b-(a+p))!=1) 如果a,b和p是正整数(假设正范围包括0值)那么表达式(((a + p)<= b)&&(a == 0 || a> 1)&&(b> = p))&&((b - (a + p)== 0)||(b - (a + p)> 1))可以简化为((a + p)<= b)&&(a! = 1) && ((b-(a + p))!= 1)

Let me demonstrate it: In the first part of the expression there is a condition, ((a+p)<=b) , that if valuated true render true the second part: ((b - (a + p) == 0) || (b - (a + p) > 1)) . 让我演示一下:在表达式的第一部分有一个条件, ((a + p)<= b) ,如果估计为真,则渲染为真第二部分: ((b - (a + p)== 0 )||(b - (a + p)> 1)) If it is true that (b >=(a+p)) then (b - (a+p)) have to be greater or equal to 0 , we need to assure that (b-(a+p))!=1 . 如果(b> =(a + p))然后(b - (a + p))必须大于或等于0 ,我们需要确保(b-(a + p))!= 1 Put this term aside for awhile and go on. 把这个术语搁置一段时间然后继续。

Now we can concentrate our efforts on the the first part (((a+p) <= b) && (a == 0 || a > 1) && (b >= p)) && ((b-(a+p))!=1) 现在我们可以集中精力在第一部分(((a + p)<= b)&&(a == 0 || a> 1)&&(b> = p)) &&((b-(a +) p))!= 1)

If a is positive then it is always >=0 and so we can drop the test (a == 0 || a > 1) if favor of (a!=1) and reduce first part of the expression to (((a+p) <= b) && (b >= p) && (a!=1)) . 如果a为正,那么它总是> = 0,因此我们可以放弃测试(a == 0 || a> 1),如果赞成(a!= 1)并将表达式的第一部分减少为(((a) + p)<= b)&&(b> = p)&&(a!= 1))

For the next step of the reduction you can consider that if b >= (a+p) then, obviously b>=p ( a is positive) and the expression can be reduced to 对于下一步的减少,你可以考虑如果b> =(a + p)那么,显然b> = pa是正的)并且表达式可以减少到

((a+p)<=b) && (a!=1) && ((b-(a+p))!=1) ((a + p)<= b)&&(a!= 1) && ((b-(a + p))!= 1)

b >= (a+p) && a>=1

即使b >= p也是多余的,因为a >= 1总是如此

关于以下逻辑如何,请评论它:

((a == 0 || a > 1) && ((b-p) > 1) )

(((a+p) <= b) && (a == 0 || a > 1) && (b >= p)) && ((b - (a + p) == 0) || (b - (a + p) > 1)) (((a + p)<= b)&&(a == 0 || a> 1)&&(b> = p))&&((b - (a + p)== 0)||(b - (a + p)> 1))

1) (a == 0 || a > 1) is (a != 1) 1)(a == 0 || a> 1)是(a!= 1)

2) (b >= p) is (b - p >= 0) 2)(b> = p)是(b - p> = 0)

(a + p <= b) is (b - p >= a), which is stronger than (b - p >= 0). (a + p <= b)是(b-p> = a),它强于(b-p> = 0)。

First condition reduced to (a != 1) && (b - p >= a) . 第一个条件减少到(a!= 1)&&(b - p> = a)

3) (b - (a + p) == 0) is (b - a - p == 0) is (b - p == a). 3)(b - (a + p)== 0)是(b-a-p == 0)是(b-p == a)。

(b - (a + p) > 1) is (b - a - p > 1) is (b - p > 1 + a). (b - (a + p)> 1)是(b-a-p> 1)是(b-p> 1 + a)。

Since we had (b - p >= a) and we're using && operation, we may say that (b - p >= a) covers (b - p == a && b - p > 1 + a). 由于我们有(b - p> = a)并且我们正在使用&&操作,我们可以说(b - p> = a)涵盖(b - p == a && b - p> 1 + a)。

Hence, the whole condition will be reduced to 因此,整个条件将减少到

(a != 1 && (b - p >= a)) (a!= 1 &&(b - p> = a))

There's a tempation to reduce it further to (b >= p), but this reduction won't cover prohibition of b = p + 1, therefore (a != 1 && (b - p >= a)) is the condition. 有一种诱惑可以将它进一步降低到(b> = p),但这种减少不会涵盖禁止b = p + 1,因此(a!= 1 &&(b - p> = a))就是条件。

This question has been pretty comfortably answered already in practice, but there is one point I mention below which I have not seen anyone else raise yet. 这个问题在实践中已经非常舒服地回答了,但是我在下面提到了一点,我还没有看到其他人提出过。

Since we were told to assume a >= 0, and the first condition assures that b - (a + p) >= 0, the bracketed || 因为我们被告知假设a = = 0,并且第一个条件确保b - (a + p)> = 0,所以括号|| tests can be turned into tests against inequality with 1: 测试可以转化为针对不平等的测试1:

(a + p <= b) && (a != 1) && (b >= p) && (b - a - p != 1) (a + p <= b)&&(a!= 1)&&(b> = p)&&(b - a - p!= 1)

It is tempting to remove the check (b >= p), which would give nickf's expression. 很容易删除支票(b> = p),这会给出nickf的表达式。 And this is almost certainly the correct practical solution. 这几乎可以肯定是正确的实际解决方案。 Unfortunately, we need to know more about the problem domain before being able to say if it is safe to do that. 不幸的是,我们需要了解有关问题域的更多信息,然后才能说出这样做是否安全。

For instance, if using C and 32-bit unsigned ints for the types of a, b, and p, consider the case where a = 2^31 + 7, p = 2^31 + 5, b = 13. We have a > 0, (a + p) = 12 < b, but b < p. 例如,如果对a,b和p的类型使用C和32位无符号整数,请考虑a = 2 ^ 31 + 7,p = 2 ^ 31 + 5,b = 13的情况。我们有一个> 0,(a + p)= 12 <b,但b <p。 (I'm using '^' to indicate exponentiation, not C bitwise xor.) (我使用'^'表示取幂,而不是C bitwise xor。)

Probably your values will not approach the kind of ranges where this sort of overflow is an issue, but you should check this assumption. 可能你的值不会接近这种溢出问题的那种范围,但你应该检查这个假设。 And if it turns out to be a possibility, add a comment with that expression explaining this so that some zealous future optimiser does not carelessly remove the (b >= p) test. 如果事实证明是可能的话,请用该表达式添加注释来解释这一点,这样一些热心的未来优化者不会随意删除(b> = p)测试。

I feel (a != 1) && (a + p <= b) && (a + p != b - 1) is slightly more clear. 我觉得(a!= 1)&&(a + p <= b)&&(a + p!= b - 1)稍微清楚一点。 Another option is: 另一种选择是:

int t = bp; int t = bp; (a != 1 && a <= t && a != t-1) (a!= 1 && a <= t && a!= t-1)

Basically a is either 0, t, or lies between 2 and t-2 inclusive. 基本上a是0,t或介于2和t-2之间(包括2和t-2)。

a!= 1 &&((b == a + p)||(b - p> a + 1))

(((a+p) <= b) && (a == 0 || a > 1) && (b >= p)) && ((b - (a + p) == 0) || (b - (a + p) > 1))

since a >=0 (positive integers), the term (a == 0 || a > 1) is always true 由于a> = 0(正整数),因此术语(a == 0 || a> 1)始终为真

if ((a+p) <= b) then (b >= p) is true when a,b,p are >=0 if((a + p)<= b)当a,b,p> = 0时,(b> = p)为真

therefore ((a+p) <= b) && (a == 0 || a > 1) && (b >= p)) && ((b - (a + p) == 0) reduces to 因此((a + p)<= b)&&(a == 0 || a> 1)&&(b> = p))&&((b - (a + p)== 0)减少到

b>=(a+p)

(b - (a + p) == 0) || (b - (a + p)== 0)|| (b - (a + p) > 1) is equivalent to b>=(a+p) (b - (a + p)> 1)相当于b> =(a + p)

therefore the whole equation reduces to 因此整个方程式减少到

**b>= (a+p)**

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM