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(模拟退火)的主要内容,如果未能解决你的问题,请参考以下文章