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; 
} 
 
 
  
原文地址:https://www.cnblogs.com/sssy/p/9643345.html