「JOISC 2020 Day4」传奇团子师傅 (假模拟退火)
感觉每次想写模拟退火,调着调着就不知道变成什么东西了
首先是分析原图,每个方案对应选择三个点,不同的方案之间显然存在排斥关系
将这些关系建立成边,问题就转化为一个 一般图最大独立集 问题
这怎么搞得定。。
因此考虑退火,每次操作随机选择一个点,检查周围的点是否选择,数一下如果自己被选,要弹掉的点的个数
同普通的退火,一开始温度高不停随机
到了后面就直接变成 选择答案不劣的方案(也就是交换两个点),事实证明这样的效率比较高
但是直接随机容易随机到选过的点,需要稍微加速一下
具体的,退火每若干次为一轮,每轮随机一个排列
在排列中从左到右找到前面(L)个未选点,然后在(L)个点中随机若干次进行决策
我是直接暴力bitset存答案的,但是效率好像还可以
因为是跑一个点调一次参数的,前面的代码都没存。。。
tips:代码对于不同数据需要修改前面三行的常量
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(){ ; }