题意:一个图,可以选择任意一个点作为起点,向外拓展成一棵树,每次拓展时的花费为边权*起点到该点(均包含)经过的·所有的点的数量,求拓展成一棵树的最小花费。
这题可以状压dp,可以搜索,可以模拟退火,但是以上所有的我都不会QAQ
这里采用随机化乱搞—— random r a n d o m _ shuffle(a+1,a+n+1), s h u f f l e ( a + 1 , a + n + 1 ) , 这个函数的意思是将序列 a a 随机打乱一次。我们进行次操作,每次根据随机后的数列进行枚举,每到一个点,就选取已开通的且到该屋子的距离*该边权最小的点。每一次操作得到一个 ans a n s ,取 min m i n 就是答案。
#include<bits/stdc++.h>
#define inf 2e9
using namespace std;
int dis[100][100],n,m,s[100];
long long minn=inf,ans;
int dep[100];
int main()
{
cin>>n>>m;
for(int i=1;i<=n;++i)
for(int j=1;j<=n;++j)
dis[i][j]=inf;
for(int i=1;i<=n;++i){
s[i]=i;
dis[i][i]=inf;
}
for(int i=1;i<=m;++i){
int x,y,d;
scanf("%d%d%d",&x,&y,&d);
if(dis[x][y]>d){
dis[x][y]=d;
dis[y][x]=d;
}
}
for(int time=1;time<=100000;++time){
ans=0;
random_shuffle(s+1,s+n+1);
memset(dep,0,sizeof(dep));
dep[s[1]]=1;//此时的根
for(int k=2;k<=n;++k){
int i=s[k],ji=0;//i枚举的是当前的屋子
long long res=inf;
for(int j=1;j<=n;++j){//j枚举的是前一个屋子
if(!dep[j]||dis[i][j]==inf)//如果前一个屋子没开||ij两个屋子之间没有边
continue;
if(res>dep[j]*dis[i][j]){
res=dep[j]*dis[i][j];
ji=j;
}
}
dep[i]=dep[ji]+1;//i点被开通
ans+=res;
}
minn=min(minn,ans);
}
cout<<minn;
return 0;
}