NOIP2017 宝藏

模拟退火这个算法最大的难点在调参-_-!

又是本机AC提交WA系列。。。

#include<cstdio>
#include<iostream>
#include<cstring>
#include<cstdlib>
#include<algorithm>
#include<cmath>
using namespace std;
typedef long long LL;
double rand_d(){return double(rand()%10000)/10000.0;}

int n,m,p[20];LL ans;
int mp[20][20]; bool o[20][20];void oc(int x,int y){o[x][y]^=1,o[y][x]^=1;}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
int prd[20],prr[20];bool prv[20];
void prim()
{
    memset(prd,63,sizeof(prd));
    memset(prv,false,sizeof(prv));
    for(int i=1;i<n;i++)
    {
        int x=0;
        for(int j=1;j<=n;j++)
            if(prv[j]==false&&(x==0||prd[x]>prd[j]))x=j;
        prv[x]=1;
        for(int y=1;y<=n;y++)
            if(prv[y]==false)
            {
                if(mp[x][y]<prd[y])
                    prd[y]=mp[x][y], prr[y]=x;
            }
    }
    memset(o,false,sizeof(o));
    for(int i=2;i<=n;i++)
        p[i-1]=i*20+prr[i],o[i][prr[i]]=o[prr[i]][i]=true;
}

//----------------------------------init---------------------------------------------------

LL sum;
void calc_dfs(int x,int fr,int dep)
{
    for(int y=1;y<=n;y++)
        if(o[x][y]&&y!=fr)
        {
            sum+=(LL)mp[x][y]*(LL)dep;
            calc_dfs(y,x,dep+1);
        }
}
LL calc()
{
    LL mmin=(1LL<<62);
    for(int i=1;i<=n;i++)
    {
        sum=0,calc_dfs(i,0,1);
        mmin=min(sum,mmin);
    }
    ans=min(ans,mmin);
    return mmin;
}

//-------------------------------calc----------------------------------------------------

int c1[20],c2[20];bool cc[20];
void gocolor(int x,int fr)
{
    cc[x]=true;c1[++c1[0]]=x;
    for(int y=1;y<=n;y++)
        if(o[x][y]&&y!=fr)
            if(cc[y]==false)gocolor(y,x);
}
void annealing()
{
    int T=1000000;
    while(T>0.01)
    {
        LL pd=calc();
        int id=rand()%(n-1)+1;
        int px=p[id]/20,py=p[id]%20;
        oc(px,py);
        
        c1[0]=0,c2[0]=0;
        memset(cc,false,sizeof(cc));
        gocolor(1,0);
        for(int i=1;i<=n;i++)
            if(cc[i]==false)c2[++c2[0]]=i;
            
        int nx=c1[rand()%c1[0]+1],ny=c2[rand()%c2[0]+1];
        oc(nx,ny);
        LL nd=calc();
        
        if(pd>nd||exp((pd-nd)/T)>rand_d())p[id]=nx*20+ny;
        else oc(px,py),oc(nx,ny);
        
        T*=0.9999;
    }
    for(int i=1;i<=1000;i++)
    {
        LL pd=calc();
        int id=rand()%(n-1)+1;
        int px=p[id]/20,py=p[id]%20;
        oc(px,py);
        
        c1[0]=0,c2[0]=0;
        memset(cc,false,sizeof(cc));
        gocolor(1,0);
        for(int i=1;i<=n;i++)
            if(cc[i]==false)c2[++c2[0]]=i;
            
        int nx=c1[rand()%c1[0]+1],ny=c2[rand()%c2[0]+1];
        oc(nx,ny);
        LL nd=calc();
        
        oc(px,py),oc(nx,ny);
    }
}

//---------------------------annealing----------------------------------------------------

int main()
{
    srand(456456);
    int x,y,dd;
    scanf("%d%d",&n,&m);
    if(n==1){printf("0\n");return 0;}
    memset(mp,63,sizeof(mp));
    for(int i=1;i<=m;i++)
    {
        scanf("%d%d%d",&x,&y,&dd);
        mp[x][y]=mp[y][x]=min(mp[x][y],dd);
    }
    
    prim(),ans=calc();
    annealing();
    printf("%lld\n",ans);
    return 0;
}

 

posted @ 2018-11-28 13:49  AKCqhzdy  阅读(134)  评论(0编辑  收藏  举报