[Luogu3936]Coloring

Luogu

sol

模拟退火呀
初始状态按顺序涂色,让同种颜色尽量放在一起。
每次随机交换两个位置,注意\(\Delta\)的计算
瞎JB调一下参数就行了
可以多做几次避免陷入局部最优解

code

#include<cstdio>
#include<algorithm>
#include<ctime>
#include<cmath>
using namespace std;
const int N = 100;
struct node{int a[25][25],tot;}ans;
int n,m,c,p[N],dx[4]={0,1,0,-1},dy[4]={1,0,-1,0};
double Rand(){return rand()%1000/1000.0;}
bool inside(int x,int y){return 1<=x&&x<=n&&1<=y&&y<=m;}
void SA(double T)
{
    node now=ans,nw;
    int x1,y1,x2,y2,d;
    while (T>1e-15)
    {
        nw=now;
        x1=1+rand()%n,y1=1+rand()%m;
        x2=1+rand()%n,y2=1+rand()%m;
        if (x1==x2&&y1==y2) continue;
        for (int d=0;d<4;d++)
            if (inside(x1+dx[d],y1+dy[d]))
                nw.tot-=(nw.a[x1][y1]!=nw.a[x1+dx[d]][y1+dy[d]]);
        for (int d=0;d<4;d++)
            if (inside(x2+dx[d],y2+dy[d]))
                nw.tot-=(nw.a[x2][y2]!=nw.a[x2+dx[d]][y2+dy[d]]);
        swap(nw.a[x1][y1],nw.a[x2][y2]);
        for (int d=0;d<4;d++)
            if (inside(x1+dx[d],y1+dy[d]))
                nw.tot+=(nw.a[x1][y1]!=nw.a[x1+dx[d]][y1+dy[d]]);
        for (int d=0;d<4;d++)
            if (inside(x2+dx[d],y2+dy[d]))
                nw.tot+=(nw.a[x2][y2]!=nw.a[x2+dx[d]][y2+dy[d]]);
        if (nw.tot<=now.tot||exp((now.tot-nw.tot)/T)>Rand()) now=nw;
        if (nw.tot<ans.tot) ans=nw;
        T*=0.99999;
    }
}
int main()
{
    scanf("%d %d %d",&n,&m,&c);
    for (int i=1;i<=c;++i) scanf("%d",&p[i]);
    for (int i=1,k=1;i<=n;i++)
        for (int j=1;j<=m;j++)
            ans.a[i][j]=p[k]?k:++k,--p[k];
    for (int i=1;i<=n;++i)
        for (int j=1;j<=m;++j)
        {
            if (i<n&&ans.a[i][j]!=ans.a[i+1][j]) ++ans.tot;
            if (j<m&&ans.a[i][j]!=ans.a[i][j+1]) ++ans.tot;
        }
    SA(1);SA(1);SA(1);
    for (int i=1;i<=n;++i,puts(""))
        for (int j=1;j<=m;++j)
            printf("%d ",ans.a[i][j]);
    return 0;
}
posted @ 2018-02-06 20:24  租酥雨  阅读(188)  评论(0编辑  收藏  举报