「JOISC 2020 Day4」传奇团子师傅 (假模拟退火)

感觉每次想写模拟退火,调着调着就不知道变成什么东西了

首先是分析原图,每个方案对应选择三个点,不同的方案之间显然存在排斥关系

将这些关系建立成边,问题就转化为一个 一般图最大独立集 问题

这怎么搞得定。。

因此考虑退火,每次操作随机选择一个点,检查周围的点是否选择,数一下如果自己被选,要弹掉的点的个数

同普通的退火,一开始温度高不停随机

到了后面就直接变成 选择答案不劣的方案(也就是交换两个点),事实证明这样的效率比较高

但是直接随机容易随机到选过的点,需要稍微加速一下

具体的,退火每若干次为一轮,每轮随机一个排列

在排列中从左到右找到前面$L$个未选点,然后在$L$个点中随机若干次进行决策

我是直接暴力bitset存答案的,但是效率好像还可以

因为是跑一个点调一次参数的,前面的代码都没存。。。

tips:代码对于不同数据需要修改前面三行的常量

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
const int N=510,M=N*N/2,INF=1e9+10;
const char infile[]="5.in",outfile[]="output_05.txt";
const int MAX=48620;

int n,m,C;
char s[N][N];
int chk(char x){ return x=='P' || x=='G'; }
struct Node{
int x,y,t;
} R[M];
bitset <M> Ansmap,Nowmap;
int ans,now;

int z[4][2]={ {0,1},{1,0},{-1,-1},{-1,1} };
char S[]="-|\\/";
vector <int> G[N][N],E[M];

struct Naive_Simulator{
~Naive_Simulator(){
cerr<<"!"<<endl;
rep(i,1,C) if(Ansmap[i]) s[R[i].x][R[i].y]=S[R[i].t];
rep(i,1,n) puts(s[i]+1);
}
int P[M],D[M],F[M],PC,counter,lst,L;
void Work(db T,db d,db End,int delta) {
while(T>End && ans<MAX) {
if(++counter%4000==0) {
cerr<<ans<<' '<<T<<endl;
}
if(counter%500==0) random_shuffle(D+1,D+C+1),lst=1;
PC=0;
rep(i,lst,C) if(!Nowmap[D[i]]) {
P[++PC]=D[i];
lst=i;
if(PC>=L) break;
}
if(PC<L) {
lst=1;
PC=0;
rep(i,lst,C) if(!Nowmap[D[i]]) {
P[++PC]=D[i];
lst=i;
if(PC>=L) break;
}
}
rep(kase,1,50) {
int u,v;
u=P[rand()%PC+1],v=P[rand()%PC+1];
if(u==v || Nowmap[u]) {
kase--;
continue;
}
int cnt=0;
for(int v:E[u]) cnt+=Nowmap[v];
if(cnt-delta<=T) {
Nowmap[u]=1;
for(int v:E[u]) Nowmap[v]=0;
now+=1-cnt;
}
if(kase%5==0 && now>ans) ans=now,Ansmap=Nowmap;
}
T*=d;
}
}
void Simulate(){
//srand(114514);
//srand(1919810);
srand(time(NULL));
now=0,Nowmap.reset();
counter=0,lst=1,L=200;
rep(i,1,C) D[i]=i;
rep(kase,1,10) Work(2,0.95,1e-2,1);
Work(0.99,0.99993,1e-8,2);
Nowmap=Ansmap,now=ans;
Work(0.99,0.99999,0,1);
return;
}

Naive_Simulator(){
freopen(infile,"r",stdin),freopen(outfile,"w",stdout);
n=rd(),m=rd();
rep(i,1,n) scanf("%s",s[i]+1);
rep(i,1,n) rep(j,1,m) if(!chk(s[i][j])) {
s[i][j]='W';
rep(d,0,3) if(chk(s[i+z[d][0]][j+z[d][1]]) && chk(s[i-z[d][0]][j-z[d][1]]) && s[i+z[d][0]][j+z[d][1]]!=s[i-z[d][0]][j-z[d][1]]) {
R[++C]=(Node){i,j,d};
G[i][j].pb(C);
G[i+z[d][0]][j+z[d][1]].pb(C);
G[i-z[d][0]][j-z[d][1]].pb(C);
}
}
rep(i,1,n) rep(j,1,m) rep(k,0,G[i][j].size()-1) rep(l,k+1,kend) {
E[G[i][j][k]].pb(G[i][j][l]);
E[G[i][j][l]].pb(G[i][j][k]);
}
Simulate();
}
} Solver;

int main(){ ; }