我们都爱膜您退火!
写了模板题(伪)洛谷P1337 平衡点,发现这跟骑行川藏毫无可比性......
骑行川藏简直就是退火地狱,这个模板题就容易的多了...随便搞几下就过了。
一些心得:
1.最好在函数值连续的时候使用模拟退火。
2.想要把精度控制的高,重要的不是eps,而是把△T调小。这样在T很小的时候会随机足够多的次数从而让精度更进一步。
3.正确性的核心在于每次随机调整出来的解的变化幅度与T相关。
例题:骑行川藏。
洛谷P1337,这东西很好退吧...
1 #include <bits/stdc++.h> 2 3 const int N = 1010; 4 const double eps = 1e-7, dT = 0.999; 5 6 struct Vec { 7 double x, y; 8 Vec(double X = 0, double Y = 0) { 9 x = X, y = Y; 10 } 11 inline Vec operator + (const Vec &w) const { 12 return Vec(x + w.x, y + w.y); 13 } 14 inline Vec operator - (const Vec &w) const { 15 return Vec(x - w.x, y - w.y); 16 } 17 inline double operator & (const Vec &w) const { 18 return x * w.x + y * w.y; 19 } 20 inline double operator * (const Vec &w) const { 21 return x * w.y - y * w.x; 22 } 23 inline Vec operator * (const double &w) const { 24 return Vec(x * w, y * w); 25 } 26 inline Vec operator / (const double &w) const { 27 return Vec(x / w, y / w); 28 } 29 }; 30 typedef Vec Poi; 31 32 Poi a[N]; 33 int n; 34 double W[N]; 35 36 inline double len(Vec x) { 37 return sqrt(x & x); 38 } 39 40 inline double cal(double x, double y) { 41 //printf("cal : %lf %lf \n", x, y); 42 Vec ans(0, 0), now(x, y); 43 for(int i = 1; i <= n; i++) { 44 if(fabs(y - a[i].y) < eps && fabs(x - a[i].x) < eps) continue; 45 Vec temp = (a[i] - now) / len(a[i] - now) * W[i]; 46 ans = ans + temp; 47 } 48 /*printf("ansx = %lf ansy = %lf \n", ans.x, ans.y); 49 puts("");*/ 50 return len(ans); 51 } 52 53 inline double Rand(double l, double r) { 54 return (double)rand() / RAND_MAX * (r - l) + l; 55 } 56 57 inline void Fire() { 58 double x1 = 1e7, x2 = -1e7, y1 = 1e7, y2 = -1e7; 59 for(int i = 1; i <= n; i++) { 60 x1 = std::min(x1, a[i].x); 61 x2 = std::max(x2, a[i].x); 62 y1 = std::min(y1, a[i].y); 63 y2 = std::max(y2, a[i].y); 64 } 65 66 double px((x2 + x1) / 2), py((y2 + y1) / 2), fx(px), fy(py), T(std::max(y2 - y1, x2 - x1)); 67 double ans = cal(px, py), fin = ans; 68 69 while(T > eps) { 70 71 double x = px + T * Rand(-1, 1), y = py + T * Rand(-1, 1); 72 x = std::max(x, x1); 73 x = std::min(x, x2); 74 y = std::max(y, y1); 75 y = std::min(y, y2); 76 double New = cal(x, y); 77 //printf("New = %lf \n", New); 78 79 if(New < fin) { 80 fin = New; 81 fx = x; 82 fy = y; 83 } 84 if(New < ans || Rand(0, 1) < exp((ans - New) / T)) { 85 ans = New; 86 px = x; 87 py = y; 88 } 89 /*printf("fin = %lf fx = %lf fy = %lf\n", fin, fx, fy); 90 printf("ans = %lf px = %lf py = %lf\n", ans, px, py); 91 printf("T = %lf New = %lf \n", T, New); 92 puts("");*/ 93 T *= dT; 94 } 95 printf("%.3f %.3f\n", fx, fy); 96 return; 97 } 98 99 int main() { 100 scanf("%d", &n); 101 for(int i = 1; i <= n; i++) { 102 scanf("%lf%lf%lf", &a[i].x, &a[i].y, &W[i]); 103 } 104 105 Fire(); 106 107 return 0; 108 }
题意:把n个小动物分成K组,使得每组的权值最大值最小。有m个约束形如两个小动物在一组会把权值 + a或者 × b,先加后乘。
解:用时约2h,得分69。
模拟退火。先随机分组,然后随机一个小动物改变到一个随机组里。权值的变化:枚举别的所有点,邻接矩阵存边权。权值的计算:每个组维护一个add和mul,暴力枚举所有组算权值。
1 #include <bits/stdc++.h> 2 3 const int N = 100010; 4 5 struct Node { 6 int x, y, f, z; 7 double w; 8 }node[N]; 9 10 inline int rd(int l, int r) { 11 return rand() % (r - l + 1) + l; 12 } 13 inline double Rand() { 14 return (double)(rand()) / RAND_MAX; 15 } 16 17 int n, K, m, val[N], val2[N], testid; 18 int fr[N], Fin[N]; 19 int G1[5010][5010], G2[5010][5010], add[N]; 20 double G3[5010][5010], mul[N]; 21 std::vector<int> v[N]; 22 23 inline double calMax() { 24 double ans(0); 25 for(register int i(1); i <= K; ++i) { 26 ans = std::max(ans, mul[i] * add[i]); 27 } 28 return ans; 29 } 30 31 inline void Fire() { 32 33 for(int i = 1; i <= K; i++) { 34 add[i] += val2[i]; 35 mul[i] = 1; 36 } 37 for(int i = 1; i <= n; i++) { 38 fr[i] = rd(1, K); 39 add[fr[i]] += val[i]; 40 for(int j = 1; j < i; j++) { 41 if(fr[i] != fr[j] || !G1[i][j]) { 42 continue; 43 } 44 if(G1[i][j] == 1) { 45 add[fr[i]] += G2[i][j]; 46 } 47 else { 48 mul[fr[i]] *= G3[i][j]; 49 } 50 } 51 } 52 53 double ans = calMax(), fin = ans; 54 memcpy(Fin + 1, fr + 1, n * sizeof(int)); 55 56 double T = 10000, dT = 0.9999, edT = 1e-7; 57 while(T > edT) { 58 59 int x = rd(1, n), y = rd(1, K); 60 while(y == fr[x]) { 61 y = rd(1, K); 62 } 63 std::swap(fr[x], y); 64 add[y] -= val[x]; 65 add[fr[x]] += val[x]; 66 for(int i = 1; i <= n; i++) { 67 if(!G1[x][i] || (fr[i] != y && fr[i] != fr[x])) { 68 continue; 69 } 70 if(fr[i] == fr[x]) { 71 if(G1[x][i] == 1) { 72 add[fr[x]] += G2[x][i]; 73 } 74 else { 75 mul[fr[x]] *= G3[x][i]; 76 } 77 } 78 else { 79 if(G1[x][i] == 1) { 80 add[y] -= G2[x][i]; 81 } 82 else { 83 mul[y] /= G3[x][i]; 84 } 85 } 86 } 87 double nex = calMax(); 88 //printf("T = %lf nex = %lf \n", T, nex); 89 if(fin > nex) { 90 fin = nex; 91 memcpy(Fin + 1, fr + 1, n * sizeof(int)); 92 printf("fin = %lf \n", fin); 93 } 94 if(nex < ans || Rand() < exp((ans - nex) / T)) { 95 ans = nex; 96 } 97 else { 98 std::swap(fr[x], y); 99 add[y] -= val[x]; 100 add[fr[x]] += val[x]; 101 for(int i = 1; i <= n; i++) { 102 if(!G1[x][i] || (fr[i] != y && fr[i] != fr[x])) { 103 continue; 104 } 105 if(fr[i] == fr[x]) { 106 if(G1[x][i] == 1) { 107 add[fr[x]] += G2[x][i]; 108 } 109 else { 110 mul[fr[x]] *= G3[x][i]; 111 } 112 } 113 else { 114 if(G1[x][i] == 1) { 115 add[y] -= G2[x][i]; 116 } 117 else { 118 mul[y] /= G3[x][i]; 119 } 120 } 121 } 122 } 123 T *= dT; 124 } 125 126 for(int i = 1; i <= n; i++) { 127 v[Fin[i]].push_back(i); 128 } 129 130 char buf[100]; 131 sprintf(buf, "spring%d.out", testid); 132 freopen(buf, "w", stdout); 133 134 for(int i = 1; i <= K; i++) { 135 int len = v[i].size(); 136 printf("%d\n", len); 137 for(int j = 0; j < len; j++) { 138 printf("%d ", v[i][j]); 139 } 140 puts(""); 141 } 142 fclose(stdout); 143 return; 144 } 145 146 int main(int argc, char **argv) { 147 148 srand(time(0)); 149 150 if(argc != 2) return 0; 151 testid = atoi(argv[1]); 152 char buf[100]; 153 sprintf(buf, "spring%d.in", testid); 154 freopen(buf, "r", stdin); 155 156 scanf("%d%d%d", &n, &K, &m); 157 for(int i = 1; i <= n; i++) { 158 scanf("%d", &val[i]); 159 } 160 for(int i = 1; i <= K; i++) { 161 scanf("%d", &val2[i]); 162 } 163 for(int i = 1; i <= m; i++) { 164 scanf("%d%d%d", &node[i].f, &node[i].x, &node[i].y); 165 int x = node[i].x, y = node[i].y; 166 G1[x][y] = G1[y][x] = node[i].f; 167 if(node[i].f == 1) { 168 scanf("%d", &node[i].z); 169 G2[x][y] = G2[y][x] = node[i].z; 170 } 171 else { 172 scanf("%lf", &node[i].w); 173 G3[x][y] = G3[y][x] = node[i].w; 174 } 175 } 176 fclose(stdin); 177 178 Fire(); 179 180 return 0; 181 }