小Y的地铁
Time Limit: 50 Sec Memory Limit: 256 MB
Description


Output
对于每组输入数据,输出一行一个整数,表示除掉这 n 个换乘站之外,最少有几个换乘站。
4
  4
  1 2 1 2
  8
  1 2 3 4 1 2 3 4
  5
  5 4 3 3 5
  8
  1 2 3 4 1 3 2 4
Sample Output
0
  0
  0
  1
HINT
n <= 44
Solution
首先,答案显然只和几个区域的连通状态有关,那么我们可以写出四种本质不同的方案。(即下图中被线分开的六块)。

我们可以考虑,对于一条线,其他线(显然仅有 部分相交 与 完全相交 两种)造成的贡献。打出表来,上图是不会造成交点的线段种类。
既然知道了这个,我们的复杂度显然可以做到 O(4 ^ (n / 2))。还是不足以通过,怎么办呢?
模拟退火大法好!
Code
| 12
 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
 
 | #include<bits/stdc++.h>using namespace std;
 typedef long long s64;
 
 const int ONE = 105;
 const int INF = 2147483640;
 
 int get()
 {
 int res = 1, Q = 1; char c;
 while( (c = getchar()) < 48 || c > 57)
 if(c == '-') Q = -1;
 if(Q) res = c - 48;
 while( (c = getchar()) >= 48 && c <= 57)
 res = res * 10 + c - 48;
 return res * Q;
 }
 
 int n, num;
 int pos[ONE], val[ONE];
 int vis[ONE], a[ONE];
 int Ans = INF;
 struct power {int l, r;} A[ONE];
 
 int x[ONE][ONE], y[ONE][ONE];
 
 void Deal_first()
 {
 x[1][2] = x[1][4] = x[1][5] = 1;
 x[2][1] = x[2][3] = x[2][6] = 1;
 x[3][1] = x[3][3] = x[3][6] = 1;
 x[4][2] = x[4][4] = x[4][5] = 1;
 for(int i = 1; i <= 4; i++) y[i][1] = y[i][2] = 1;
 }
 
 int Now;
 
 int Judge(int pos, int type)
 {
 int res = Now;
 for(int i = pos, j = pos + 1; j <= num; j++)
 {
 if(A[i].r < A[j].l) continue;
 if(A[i].r < A[j].r) res -= !x[a[i]][a[j]];
 if(A[j].r < A[i].r) res -= !y[a[i]][a[j]];
 }
 for(int i = 1, j = pos; i < pos; i++)
 {
 if(A[i].r < A[j].l) continue;
 if(A[i].r < A[j].r) res -= !x[a[i]][a[j]];
 if(A[j].r < A[i].r) res -= !y[a[i]][a[j]];
 }
 
 a[pos] = type;
 
 for(int i = pos, j = pos + 1; j <= num; j++)
 {
 if(A[i].r < A[j].l) continue;
 if(A[i].r < A[j].r) res += !x[a[i]][a[j]];
 if(A[j].r < A[i].r) res += !y[a[i]][a[j]];
 }
 for(int i = 1, j = pos; i < pos; i++)
 {
 if(A[i].r < A[j].l) continue;
 if(A[i].r < A[j].r) res += !x[a[i]][a[j]];
 if(A[j].r < A[i].r) res += !y[a[i]][a[j]];
 }
 
 Now = res, Ans = min(Ans, res);
 return res;
 }
 
 double Random() {return (double)rand() / RAND_MAX;}
 void SA()
 {
 if(num == 0) return;
 double T = num * 2;
 while(T >= 0.01)
 {
 int pos = rand() % num + 1, type = rand() % 4 + 1;
 int ori = Now, ori_type = a[pos];
 
 int dE = Judge(pos, type) - ori;
 if(dE <= 0 || Random() <= exp(-dE / T)) a[pos] = type;
 else Judge(pos, ori_type);
 
 T *= 0.9993;
 }
 }
 
 void Deal()
 {
 Ans = INF;
 n = get();
 for(int i = 1; i <= n; i++) a[i] = get(), pos[a[i]] = vis[a[i]] = 0;
 for(int i = n; i >= 1; i--)
 if(!pos[a[i]]) pos[a[i]] = i;
 
 num = 0;
 for(int i = 1; i <= n; i++)
 if(!vis[a[i]] && pos[a[i]] != i)
 A[++num] = (power){i, pos[a[i]]}, vis[a[i]] = 1;
 
 for(int i = 1; i <= num; i++)
 a[i] = rand() % 4 + 1;
 Ans = 0;
 for(int i = 1; i <= num; i++)
 for(int j = i + 1; j <= num; j++)
 {
 if(A[i].r < A[j].l) break;
 if(A[i].r < A[j].r) Ans += !x[a[i]][a[j]];
 if(A[j].r < A[i].r) Ans += !y[a[i]][a[j]];
 }
 Now = Ans;
 for(int i = 1; i <= 10; i++)
 SA();
 printf("%d\n", Ans);
 }
 
 int main()
 {
 Deal_first();
 int T = get();
 while(T--)
 Deal();
 }
 
 |