NOIP2017 宝藏

题目传送门

感觉这个题被玩坏了……
翻看了一下题解区,发现了\(N\)种神仙做法:

  1. 随机化搜索(伪模拟退火)
  2. 搜索+剪枝
  3. 模拟退火
  4. 不对但是能A的状压\(DP\)
  5. 正确的状压\(DP\)
    其中\(DP\)又分用\(DFS\)的\(DP\),不用\(DFS\)的\(DP\),而且各种\(DP\)的时间复杂度也各不相同……

我还有什么话可说呢?


学习科学,使用玄学
——zhx

既然标签上都写了搜索和随机化了,那我们肯定要用第一种神仙做法(其实是因为我看不懂状压DP)

这里的随机化用到了一点模拟退火的思想,以一定的概率去接受新的连边方式,这个概率是随着\(n\)的上升而增大的
为了寻找最优解,我们可以让它多跑几遍,取最小值

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<queue>
#define inf 1000000
using namespace std;
int g[15][15],deth[15];
struct zzz{
    int f,t;
}pass[1010]; int top;
bool operator < (struct zzz a,struct zzz b){
    return deth[a.f]*g[a.f][a.t] > deth[b.f]*g[b.f][b.t];
}
bool vis[15];
int n,m;
int bfs(int s){
    priority_queue <zzz> q;
    int cost=0;
    //将一开始的边入堆
    for(int i=1;i<=n;i++)
      if(g[s][i]<inf)
        q.push(zzz{s,i});
    //因为要多加(n-1)条边,所以循环到n-1
    for(int i=1;i<n;i++){
        zzz e=q.top(); q.pop();
        while(!q.empty()&&(vis[e.t]||(rand()%n<1))){ //随机找边
            if(!vis[e.t]) pass[++top]=e;  //跳过的边仍然可能用到,先将它们存起来
            e=q.top(); q.pop();  //随机一条新边
        }
        vis[e.t]=1; deth[e.t]=deth[e.f]+1;
        for(int i=1;i<=top;i++)  //将之前跳过的边在怼进堆里
          q.push(pass[i]);
        top=0;
        for(int i=1;i<=n;i++)
          if(g[e.t][i]<inf&&!vis[i])  //扩展新的边
            q.push(zzz{e.t,i});
        cost+=g[e.f][e.t]*deth[e.f];
    }
    return cost;
}
int read(){
    int k=0; char c=getchar();
    while(c<'0'||c>'9') c=getchar();
    while(c>='0'&&c<='9')
      k=k*10+c-48, c=getchar();
    return k;
}
int main(){
    srand(19****17); //打码保平安
    memset(g,127/3,sizeof(g));
    n=read(),m=read();
    for(int i=1;i<=m;i++){  //因为点少边多,使用邻接矩阵存图更为方便
        int x=read(),y=read();
        g[x][y]=g[y][x]=min(g[x][y],read());
    }
    int ans=0x7fffffff;
    for(int i=1;i<=500;i++)  //为寻找最优解,多跑几遍
      for(int i=1;i<=n;i++){  //枚举根节点
          //初始化
          memset(deth,127/3,sizeof(deth));
          memset(vis,0,sizeof(vis));
          deth[i]=vis[i]=1; top=0;
          ans=min(ans,bfs(i))
      }
    cout<<ans;
    return 0;
}
上一篇:SQL中如何使用EXISTS替代IN


下一篇:soup 查找网页所有A的href