Luogu3936 Coloring(模拟退火)

Posted gloid

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Luogu3936 Coloring(模拟退火)相关的知识,希望对你有一定的参考价值。

  裸退火,每次交换两个格子即可。依旧不会调参,稍微抄了点参数并且把随机种子设成了一个神奇的数字终于过掉了

#include<iostream> 
#include<cstdio>
#include<cmath>
#include<cstdlib>
#include<cstring>
#include<algorithm>
#include<ctime>
using namespace std;
#define ll long long
#define N 22
#define M 55
#define T0 1
#define T1 1E-14
#define delta 0.9999
char getc(){char c=getchar();while ((c<A||c>Z)&&(c<a||c>z)&&(c<0||c>9)) c=getchar();return c;}
int gcd(int n,int m){return m==0?n:gcd(m,n%m);}
int read()
{
    int x=0,f=1;char c=getchar();
    while (c<0||c>9) {if (c==-) f=-1;c=getchar();}
    while (c>=0&&c<=9) x=(x<<1)+(x<<3)+(c^48),c=getchar();
    return x*f;
}
int n,m,c,a[M],color[N][N],cnt,ans,goal[N][N];
int wx[4]={1,0,0,-1},wy[4]={0,1,-1,0};
int calc(int x,int y)
{
    int t=0;
    for (int k=0;k<4;k++)
    if (x+wx[k]>=1&&x+wx[k]<=n&&y+wy[k]>=1&&y+wy[k]<=m)
        if (color[x][y]!=color[x+wx[k]][y+wy[k]]) t++;
    return t;
}
void anneal()
{
    double T=T0;
    while (T>T1)
    {
        int x1=rand()%n+1,y1=rand()%m+1,x2=rand()%n+1,y2=rand()%m+1;
        while (x1==x2||y1==y2) x1=rand()%n+1,y1=rand()%m+1,x2=rand()%n+1,y2=rand()%m+1;
        int d=0;
        d-=calc(x1,y1),d-=calc(x2,y2);
        swap(color[x1][y1],color[x2][y2]);
        d+=calc(x1,y1),d+=calc(x2,y2);
        if (d<0||rand()<exp(-d/T)*RAND_MAX) cnt+=d;
        else swap(color[x1][y1],color[x2][y2]);
        if (cnt<ans) ans=cnt,memcpy(goal,color,sizeof(color));
        T*=delta;
    }
}
int main()
{
#ifndef ONLINE_JUDGE
    freopen("color.in","r",stdin);
    freopen("color.out","w",stdout);
    const char LL[]="%I64d
";
#else
    const char LL[]="%lld
";
#endif
    n=read(),m=read(),c=read();
    srand(20020509);
    for (int i=1;i<=c;i++) a[i]=read();
    int x=1,y=1;
    for (int i=1;i<=c;i++)
    while (a[i])
    {
        color[x][y]=i;
        a[i]--;y++;
        if (y>m) x++,y=1;
    }
    for (int i=1;i<=n;i++)
        for (int j=1;j<=m;j++)
            for (int k=0;k<4;k++)
            if (i+wx[k]>=1&&i+wx[k]<=n&&j+wy[k]>=1&&j+wy[k]<=m)
                if (color[i][j]!=color[i+wx[k]][j+wy[k]]) cnt++;
    ans=cnt>>=1;
    memcpy(goal,color,sizeof(color));
    for (int i=1;i<=20;i++) anneal();
    for (int i=1;i<=n;i++)
    {
        for (int j=1;j<=m;j++)
        cout<<goal[i][j]<< ;
        cout<<endl;
    }
    return 0;
}

 

以上是关于Luogu3936 Coloring(模拟退火)的主要内容,如果未能解决你的问题,请参考以下文章

cf2c(模拟退火 步长控制

Matlab模拟退火+最低水平线解决物流上的二维装箱问题

[Luogu] 宝藏

[JSOI2004]平衡点

模拟D. 3-Coloring——Codeforces Round #712 (Div. 2)

浅谈模拟退火