Пример #1
0
        private void Expand(Dir[,] choice, int r, int c, int from, int to, int totalScore, int stage, int mask)
        {
            if (r == n_)
            {
                from *= 3;
                to *= 3;
                int fromStart = 0, fromEnd = 2;
                if ((stage & 0x1) > 0)
                {
                    // can only accept states with no start or end
                    fromEnd = 0;
                }
                else if (stage == 0x2)
                {
                    // has end in the column but no start, can only accept states with start (only)
                    fromStart = 1;
                    fromEnd = 1;
                }

                int toAdd = 0;
                if ((stage & 0x2) > 0) toAdd = 2;
                else if (stage == 0x1) toAdd = 1;

                for (int fromAdd = fromStart; fromAdd <= fromEnd; fromAdd++)
                {
                    List<Entry> parents = prev_[from + fromAdd];

                    for (int i = 0; i < parents.Count; i++)
                    {
                        int currentScore = parents[i].score + totalScore;

                        DisjointSet groups = new DisjointSet(n_);
                        bool invalid = false;
                        for (int j = 0; j < n_; j++)
                        {
                            if (choice[j, 0] == Dir.Down || choice[j, 1] == Dir.Up)
                            {
                                groups.Union(j, j - 1);
                            }
                            if (choice[j, 0] == Dir.Left || choice[j, 1] == Dir.Right)
                            {
                                // find out whether the rhs has connected to anything above it
                                int rhs = (parents[i].groups >> j * 2) & 0x3;
                                int connected = -1;
                                for (int k = j - 1; k >= 0; k--)
                                {
                                    if (choice[k, 0] == Dir.Left || choice[k, 1] == Dir.Right)
                                    {
                                        if (((parents[i].groups >> k * 2) & 0x3) == rhs)
                                        {
                                            connected = k;
                                            break;
                                        }
                                    }
                                }
                                if (connected != -1)
                                {
                                    invalid |= !groups.Union(connected, j);
                                    // this forms a closed loop, which is an invalid formation
                                    if (invalid) break;
                                }
                                // else rhs does not connect to anything above it
                            }
                        }

                        if (invalid) continue;

                        toAdd = Math.Max(toAdd, fromAdd);
                        List<Entry> current = next_[to + toAdd];
                        int toGroups = groups.Normalize(mask);
                        bool fnd = false;
                        var currentSolution = parents[i].solution.Select(s => s).ToList();
                        currentSolution.Add((Dir[,])choice.Clone());
                        for (int j = 0; j < current.Count; j++)
                        {
                            if (current[j].groups == toGroups)
                            {
                                if (currentScore > current[j].score)
                                {
                                    current[j].score = currentScore;
                                    current[j].solution = currentSolution;
                                }
                                fnd = true;
                                break;
                            }
                        }
                        if (!fnd)
                        {
                            current.Add(new Entry(toGroups, currentScore, currentSolution));
                        }
                    }
                }

                return;
            }

            for (int k = 0; k < Dirs.Values.GetLength(0); k++)
            {
                if (grid_[r, c] == 0 && k > 0) break;
                if (stage == 1 && Dirs.Values[k, 0] == Dir.None && k > 0) break;
                if ((stage & 0x2) > 0 && Dirs.Values[k, 1] == Dir.None && k > 0) break;

                if (r > 0 &&
                (choice[r - 1, 0] == Dir.Up && Dirs.Values[k, 1] != Dir.Up || choice[r - 1, 1] == Dir.Down && Dirs.Values[k, 0] != Dir.Down))
                    continue;
                if (Dirs.Values[k, 0] == Dir.Down && (r == 0 || choice[r - 1, 1] != Dir.Down)) continue;
                if (Dirs.Values[k, 1] == Dir.Up && (r == 0 || choice[r - 1, 0] != Dir.Up)) continue;
                if (Dirs.Values[k, 1] == Dir.Down && r == n_ - 1) continue;
                if (Dirs.Values[k, 0] == Dir.Up && r == n_ - 1) continue;

                choice[r, 0] = Dirs.Values[k, 0];
                choice[r, 1] = Dirs.Values[k, 1];

                int fromBit = 0;
                int toBit = 0;

                if (choice[r, 0] == Dir.Left)
                {
                    fromBit = 1;
                }
                else if (choice[r, 1] == Dir.Right)
                {
                    fromBit = 2;
                }
                if (choice[r, 0] == Dir.Right)
                {
                    toBit = 2;
                }
                else if (choice[r, 1] == Dir.Left)
                {
                    toBit = 1;
                }

                int nextStage = stage;
                if (Dirs.Values[k, 0] == Dir.None && k > 0) nextStage |= 0x1;
                else if (Dirs.Values[k, 1] == Dir.None && k > 0) nextStage |= 0x2;

                int nextMask = mask;
                if (choice[r, 1] == Dir.Left || choice[r, 0] == Dir.Right)
                {
                    nextMask |= 1 << r;
                }
                Expand(choice, r + 1, c, from * 3 + fromBit, to * 3 + toBit, k == 0 ? totalScore : totalScore + grid_[r, c], nextStage, nextMask);
            }
        }