summaryrefslogtreecommitdiff
path: root/Assets/Algorithms/Recursion/Recursion_DC.cs
blob: 7dc873d1206a00c07b4b1522088019f8b02211f0 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
using System;
using System.Collections;
using System.Collections.Generic;
using AlgorithmCollection;
using UnityEngine;

// 分治算法
namespace AlgorithmCollection.Recursion
{

    public static partial class RecursionHelper
    {

        #region 分治框架
        public delegate DivisionDescriptor Init();
        public delegate void Solve(DivisionDescriptor division);
        public delegate bool Divide(DivisionDescriptor division, out DivisionDescriptor[] divs);//返回值代表是否达到最小问题阈值
        public delegate void Merge(DivisionDescriptor[] divisions);
        public delegate void Postprocess(DivisionDescriptor div);

        // 分治算法框架
        public static void DC(Init init, Divide divide, Solve solve, Postprocess postprocess = null, Merge merge = null)
        {
            DivisionDescriptor div = init();
            _DivideAndConquer(div, solve, divide, merge, postprocess);
        }

        // 处理单个任务
        private static void _DivideAndConquer(DivisionDescriptor div, Solve solve, Divide divide, Merge merge, Postprocess postprocess)
        {
            DivisionDescriptor[] division;
            bool bUnit = divide(div, out division);
            if (!bUnit)
            {
                for (int i = 0; i < division.Length; ++i)
                {
                    _DivideAndConquer(division[i], solve, divide, merge, postprocess);
                    postprocess?.Invoke(division[i]);
                }
                merge?.Invoke(division);
            }
            else
            {
                for (int i = 0; i < division.Length; ++i)
                {
                    solve(division[i]);
                }
            }
        }
        #endregion

        #region 全排列,返回数据的所有组合
        public static void Permutations<T>(List<T> dataList, ref List<List<T>> perms)
        {
            List<List<T>> outPerms = new List<List<T>>();                            //  A B C D 
            List<T> temp = new List<T>(dataList.Count);                              //  + A (BCD)
            DC(                                                                     //  	+ B (CD)
                () => // init                                            	         //  		+ C(D)
                {                                                                    //  			+D
                    DivisionDescriptor div = new DivisionDescriptor();               //  		+ D(C)
                    div.userdata = -1;                                               //  			+C
                    div.left = 0;                                                    //  	+ C (BD)
                    div.right = dataList.Count - 1;                                  //  		+ B(D)
                    return div;                                                      //  		+ D(B)
                },                                                                   //  	+ D (BC)
                (DivisionDescriptor div, out DivisionDescriptor[] divs) => // 划分   //  		+ B(C)
                {                                                                    //  		+ C(B)
                    int left = div.left; // 包含第一个元素在内的范围			         //  + B (ACD)
                    int right = div.right;                                           //  + C (ABD)
                    int pivot = (int)div.userdata; // 第一个元素在范围内的索引         //  + D (ABC)
                    int l = left;
                    if (pivot != -1)
                    {
                        temp.Add(dataList[pivot]);
                        Algorithms.Swap(ref dataList, pivot, left);
                        l = left + 1;
                    }
                    divs = new DivisionDescriptor[right - l + 1];
                    int j = 0;
                    for (int i = l; i <= right; ++i)
                    {
                        divs[j].left = l;
                        divs[j].right = right;
                        divs[j].userdata = (int)i;
                        j++;
                    }
                    return l == right;
                },
                (DivisionDescriptor div) => // solve 最小子任务处理   
                {
                    temp.Add(dataList[div.left]);
                    List<T> newCompose = new List<T>(temp);
                    outPerms.Add(newCompose);
                    temp.RemoveAt(temp.Count - 1);
                },
                (DivisionDescriptor div) => //子任务后处理
                {
                    int pivot = (int)div.userdata; // 第一个元素的索引
                    int left = div.left;
                    int right = div.right;
                    Algorithms.Swap(ref dataList, pivot, left);
                    temp.RemoveAt(temp.Count - 1);
                }
            );
            perms = outPerms;
        }

        // 生成器形式,每次返回一个组合
        public static IEnumerable Permutations<T>(List<T> data)
        {
            foreach (var perm in _Permutations(data, 0, data.Count - 1))
            {
                yield return perm;
            }
        }

        // 计算start~end范围内的全排列
        private static IEnumerable _Permutations<T>(List<T> data, int start, int end, List<T> perm = null)
        {
            if (perm == null)
                perm = new List<T>(data.Count);
            if (start == end)
            {
                perm.Add(data[start]);
                yield return perm;
                perm.RemoveAt(perm.Count - 1);
            }
            else
            {
                for (int i = start; i <= end; ++i)
                {
                    perm.Add(data[i]);
                    Algorithms.Swap(ref data, start, i);
                    IEnumerator itor = _Permutations(data, start + 1, end, perm).GetEnumerator();
                    while (itor.MoveNext())
                        yield return itor.Current;
                    Algorithms.Swap(ref data, start, i);
                    perm.RemoveAt(perm.Count - 1);
                }
            }
        }
        #endregion
    }
}