luogu P3959 宝藏

Posted sssy

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了luogu P3959 宝藏相关的知识,希望对你有一定的参考价值。

题目链接

luogu P3959 宝藏

题解

开始写了个random_shuffle竟然水了70,然后退火一下就A了?
每次做生成树的时候,随机两条边的顺序交换
退火一下,就A了

代码

#include<cmath> 
#include<cstdio> 
#include<ctime> 
#include<cstring> 
#include<algorithm> 
inline int read() { 
    int x = 0,f = 1; 
    char c = getchar(); 
    while(c < '0' || c > '9')c = getchar(); 
    while(c <= '9' && c >= '0') x = x * 10 + c - '0',c = getchar(); 
    return x * f; 
}
const int maxn = 13; 
#define INF 0x7fffffff
int n,m;
int mp[maxn][maxn]; 
#define IT = 5; 
struct node { 
    int u,v,w,next; 
    bool operator < (const node & a)const { 
        return w < a.w; 
    } 
} E[maxn * maxn],edge[maxn * maxn]; 
int num = 0,head[maxn]; 
inline void add_edge(int u,int v,int w) { 
    edge[++ num].v = v; edge[num].w = w; edge[num].next = head[u];head[u] = num; 
} 
int fa[maxn]; 
int find(int x) { 
    if(fa[x] != x) fa[x] = find(fa[x]); 
    return fa[x]; 
} 

int f[maxn]; 
int tot = 0; 
int calc(int x,int fa,int num) { 
    int ans = 0; 
    for(int i = head[x];i;i = edge[i].next) { 
        int v = edge[i].v; 
        if(v == fa) continue; 
        ans += edge[i].w * num; 
        ans += calc(v,x,num + 1); 
    } 
    return ans; 
} 
#define T 100000
#define delta 0.97 
#define eps 1e-10
int solve() { 
    int ret = INF; 
    for(int i = 1;i <= n;++ i) fa[i] = i,head[i] = 0;  num = 0; 
    int cnt = 0;  
    for(int i = 1;i <= tot;++ i) { 
        int u = find(E[i].u),v = find(E[i].v); 
        if(u != v) { 
            fa[u] = v; 
            add_edge(E[i].u,E[i].v,E[i].w); 
            add_edge(E[i].v,E[i].u,E[i].w); 
            cnt ++; 
        }   
        if(cnt == n - 1) break; 
    } 
    if(cnt != n - 1) return INF; 
    for(int i = 1;i <= n;++ i) ret = std::min(ret,calc(i,i,1)); 
    return ret; 
} 
int main() { 
    srand(20010901); 
    n = read(),m = read(); 
    memset(mp,0x3f,sizeof mp); 
    for(int u,v,w,i = 1;i <= m;++ i) { 
        u = read(),v = read(),w = read(); 
        mp[u][v] = mp[v][u] = std::min(mp[u][v],w); 
    } 
    for(int i = 1;i <= n;++ i) 
        for(int j = i + 1;j <= n;++ j) 
        if(mp[i][j] < 0x3f3f3f3f) E[++ tot] = (node) {i,j,mp[i][j]}; 
    if(tot == 0) { 
        printf("0"); 
        return 0; 
    } 
    std::sort(E + 1,E + tot + 1); 
    int ans = solve(); 
    
    for(int i = 1;i <= 200;++ i) { 
        int now = INF; double t = T; 
        for(;t > eps;t *= delta) { 
            int loc1 = rand() % tot + 1,loc2 = rand() % tot + 1; 
            std::swap(E[loc1],E[loc2]);  
            int nxans = solve(); 
            if(nxans < now || (exp(now - nxans / t) < (rand() / RAND_MAX))) now = nxans; 
            else std::swap(E[loc1],E[loc2]);  
        } 
        ans = std::min(ans,now); 
    } 
    printf("%d
",ans); 
    return 0; 
} 
 
 
  

以上是关于luogu P3959 宝藏的主要内容,如果未能解决你的问题,请参考以下文章

LOJ P3959 宝藏 状压dp noip

P3959 宝藏

P3959 宝藏

题解P3959 宝藏 - 状压dp / dfs剪枝

P3959 [NOIP2017 提高组] 宝藏

题解 P3959 宝藏