• 题解 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;
    }
    
  • 相关阅读:
    正点原子的串口助手XCOM V2.0编码问题
    切图设计工具软件或平台
    Notepad++插件
    emWin调用GUI_PNG_Draw方法显示PNG图片
    C语言-结构体冒号(:)位域
    Keil报错:error: #130: expected a "{"
    Doxygen简明注释语法
    Ubuntu连接不上Xshell
    Springboot注解的作用
    idea常用快捷键
  • 原文地址:https://www.cnblogs.com/martian148/p/13328804.html
Copyright © 2020-2023  润新知