题解 P2538 【[SCOI2008]城堡】

P2538 [SCOI2008]城堡

solve

被模拟退火的标签吸引来了,没想到是一道黑题,就被我用模拟退火水过去了。

我们可以把没有城堡的城市看成是一个序列,序列的前k项我们可以用来做城堡,我可以先用Floyd预处理出每个点之间的距离,然后用(n^2)的时间统计出此时的(max(dis x))所以模拟退火每次交换序列中的两个元素就好了。

code

#include<iostream>
#include<cstdio>
#include<stdlib.h>
#include<cmath>
#include<ctime>
#define rep(i,a,b) for(register int i=a;i<=b;i++)
#define maxn 500
#define inf 0x3f3f3f3f
#define delta 0.996
using namespace std;

inline int read() {
    int f=1,x=0;
    char ch=getchar();
    while(ch<'0'||ch>'9') {if(ch=='-') f=-f;ch=getchar();}
    while('0'<=ch&&ch<='9') x=(x<<3)+(x<<1)+ch-'0',ch=getchar();
    return x*f;
} 

void write(int x) {
    if(x<0) x=-x,putchar('-');
    if(x>9) write(x/10);
    putchar(x%10+'0');
}

struct edge{
    int a,b,next,v;
}e[maxn];
int head[maxn],cnt,n,m,k,v[maxn],cas[maxn];
int dis[maxn][maxn],p[maxn],N,X[maxn],ans=1e8;
double t;

int calculate(int x[]) {
    rep(i,1,k) cas[x[i]]=1;
    int res=-inf;
    rep(i,0,n) {
        int minn=inf;
        rep(j,0,n) if(cas[j]) minn=min(minn,dis[i][j]);
        res=max(res,minn);
    }
    rep(i,1,k) cas[x[i]]=0;
    return res;
}

void simulate_anneal() {
    int a[maxn];
    rep(i,1,N) a[i]=p[i];
    t=5000;
    while(t>1e-15) {
        int b[maxn];
        rep(i,1,N) b[i]=a[i];
        int x=rand()%N+1;
        int y=rand()%N+1;
        swap(b[x],b[y]);
        int now=calculate(b);
        double Delta=now-ans;
        if(Delta<0) {
            ans=now;
            rep(i,1,N) p[i]=a[i]=b[i];
        } else if(exp(-Delta/t)*RAND_MAX>rand()) {
            rep(i,1,N) a[i]=b[i];
        }
        t*=delta;
    }
}

void work() {
	while((double)clock()/CLOCKS_PER_SEC<=0.6)simulate_anneal();
}

int main() {
	freopen(".in","r",stdin);
	freopen(".out","w",stdout);
    srand(time(0));
    n=read(),m=read(),k=read();
    n--;
    rep(i,0,n) X[i]=read();
    rep(i,0,n) v[i]=read();
    rep(i,1,m) {
        int a=read();
        cas[a]=1;
    }
    rep(i,0,n) if(!cas[i]) p[++N]=i;
    rep(i,0,n) rep(j,0,n) dis[i][j]=inf;
    rep(i,0,n) dis[i][X[i]]=dis[X[i]][i]=min(v[i],dis[i][X[i]]),dis[i][i]=0;
    rep(c,0,n) rep(i,0,n) rep(j,0,n)
    dis[i][j]=min(dis[i][j],dis[i][c]+dis[c][j]);
    work();
    write(ans);
    return 0;
}
原文地址:https://www.cnblogs.com/martian148/p/13328804.html