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

「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(){ ; }
posted @ 2021-03-17 14:28  chasedeath  阅读(196)  评论(0编辑  收藏  举报