public unsafe string AnnealOnConstCurve() { const int len = Const.N + 2; int * distance = stackalloc int[len << 7]; var curve = Util.HilvertCurve.ToArray(); for (int i = 1; i <= Const.N; i++) { var(iby, ibx) = Board[i]; var(icy, icx) = curve[i - 1]; for (int j = 1; j <= Const.N; j++) { var(jby, jbx) = Board[j]; var(jcy, jcx) = curve[j - 1]; var dist = Abs(iby - jby) + Abs(ibx - jbx) + Abs(icy - jcy) + Abs(icx - jcx); distance[(i << 7) + j] = dist; } } for (int i = 1; i <= Const.N; i++) { // Init cost var(iby, ibx) = Board[i]; var(icy, icx) = curve[i - 1]; int minBY = Min(iby, 19 - iby); int minBX = Min(ibx, 19 - ibx); int minCY = Min(icy, 9 - icy); int minCX = Min(icx, 9 - icx); var cost = Min(Max(minCY - minBY, 0) + Max(minCX - minBX, 0), Max(minCY - minBX, 0) + Max(minCX - minBY, 0)); //if (0 < cost) cost += 8; //原点からの距離/一番最後にカーブに置くものから0への距離が必要 distance[(0 << 7) + i] = iby + ibx + icy + icx; distance[(i << 7) + (len - 1)] = 0; } //0がスタート、n+2がゴール int ind = 1; Span <int> cur = stackalloc int[len]; bool[] used = new bool[len]; for (int i = 0; i < Const.H; i += 4) { int begin, end, d; if ((i / 4) % 2 == 0) { (begin, end, d) = (0, Const.W, 1); } else { (begin, end, d) = (Const.W - 1, -1, -1); } for (int j = begin; j != end; j += d) { int nbegin, nend, nd; if (j % 2 != 0) { (nbegin, nend, nd) = (i, i + 4, 1); } else { (nbegin, nend, nd) = (i + 3, i - 1, -1); } for (int k = nbegin; k != nend; k += nd) { if (Board[k, j] != 0) { cur[ind++] = Board[k, j]; } } } } cur[ind] = len - 1; int curCost = 0; for (int i = 0; i < len - 1; i++) { curCost += distance[(cur[i] << 7) + cur[i + 1]]; } curCost += 100 - 1; Span <int> minRes = stackalloc int[len]; cur.CopyTo(minRes); int minCost = curCost; #region Anneal #if TRUE const double startTemp = 16.4; const double endTemp = 0.15; int cnt = 0; double temp = 0; var muler = (1 / 0.975) / Const.TL; while (true) { if ((cnt & 1024) == 0) { var progress = (double)(DateTime.Now - StartAt).TotalSeconds * muler; temp = startTemp + (endTemp - startTemp) * progress; if (1 <= progress) { break; } } cnt++; int a = RNG.Next() % Const.N, b; do { b = RNG.Next() % Const.N; } while (b == a); // a < b if (a > b) { (a, b) = (b, a); } a++; b++; var curdist = distance[(cur[a - 1] << 7) + cur[a]] + distance[(cur[b] << 7) + cur[b + 1]]; var nxtdist = distance[(cur[a - 1] << 7) + cur[b]] + distance[(cur[a] << 7) + cur[b + 1]]; //curdistの方が大きいと嬉しいよ 大きいと正になるのはcurdist - nxtdist var prob = Exp((curdist - nxtdist) / temp); if (prob * uint.MaxValue > RNG.UInt) { MemoryExtensions.Reverse(cur.Slice(a, b - a + 1)); curCost = curCost - curdist + nxtdist; if (curCost < minCost) { cur.CopyTo(minRes); minCost = curCost; } } }
public unsafe string AnnealOnConstCurve() { const int len = Const.N + 2; int * distance = stackalloc int[len << 7]; var curve = Util.HilvertCurve.ToArray(); for (int i = 1; i <= Const.N; i++) { var(iby, ibx) = Board[i]; var(icy, icx) = curve[i - 1]; for (int j = 1; j <= Const.N; j++) { var(jby, jbx) = Board[j]; var(jcy, jcx) = curve[j - 1]; var dist = Abs(iby - jby) + Abs(ibx - jbx) + Abs(icy - jcy) + Abs(icx - jcx); distance[(i << 7) + j] = dist; } } for (int i = 1; i <= Const.N; i++) { var(iby, ibx) = Board[i]; var(icy, icx) = curve[i - 1]; var(zcy, zcx) = curve[0]; var maxdist = new[] { icy, 9 - icy, icx, 9 - icx }.Max(); //原点からの距離/一番最初に取るものから0への距離が必要 distance[(0 << 7) + i] = iby + ibx + Abs(zcy - icy) + Abs(zcx - icx); distance[(i << 7) + (len - 1)] = Max(0, 5 - maxdist); } //0がスタート、n+2がゴール Span <int> cur = stackalloc int[len]; for (int i = 0; i < len; i++) { cur[i] = i; } int curCost = 0; for (int i = 0; i < len - 1; i++) { curCost += distance[(cur[i] << 7) + cur[i + 1]]; } curCost += 100 - 1; Span <int> minRes = stackalloc int[len]; cur.CopyTo(minRes); int minCost = curCost; #region Anneal #if TRUE const double startTemp = 16.4; const double endTemp = 0.15; int cnt = 0; double temp = 0; var muler = (1 / 0.975) / Const.TL; while (true) { if ((cnt & 1024) == 0) { var progress = (double)(DateTime.Now - StartAt).TotalSeconds * muler; temp = startTemp + (endTemp - startTemp) * progress; if (1 <= progress) { break; } } cnt++; int a = RNG.Next() % Const.N, b; do { b = RNG.Next() % Const.N; } while (b == a); // a < b if (a > b) { (a, b) = (b, a); } a++; b++; var curdist = distance[(cur[a - 1] << 7) + cur[a]] + distance[(cur[b] << 7) + cur[b + 1]]; var nxtdist = distance[(cur[a - 1] << 7) + cur[b]] + distance[(cur[a] << 7) + cur[b + 1]]; //curdistの方が大きいと嬉しいよ 大きいと正になるのはcurdist - nxtdist var prob = Exp((curdist - nxtdist) / temp); if (prob * uint.MaxValue > RNG.UInt) { MemoryExtensions.Reverse(cur.Slice(a, b - a + 1)); curCost = curCost - curdist + nxtdist; if (curCost < minCost) { cur.CopyTo(minRes); minCost = curCost; } } }