随机化乱搞 NOIP 2017 宝藏

16 篇文章 0 订阅
6 篇文章 0 订阅

题意:一个图,可以选择任意一个点作为起点,向外拓展成一棵树,每次拓展时的花费为边权*起点到该点(均包含)经过的·所有的点的数量,求拓展成一棵树的最小花费。

这题可以状压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 随机打乱一次。我们进行100000次操作,每次根据随机后的数列进行枚举,每到一个点,就选取已开通的且到该屋子的距离*该边权最小的点。每一次操作得到一个 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;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值