【洛谷P3959】[NOIP2017] 宝藏

宝藏

题目链接

 

首先,打了一个prim,得了45分

 

 1 #include<iostream>
 2 #include<cstring>
 3 #include<cstdio>
 4 #include<queue>
 5 using namespace std;
 6 #define N 15
 7 #define M 2000
 8 #define INF 0x3f3f3f3f
 9 int n,m,dis[N],dep[N],ans;
10 int Head[N],tot;
11 bool vis[N];
12 struct NODE{
13     int to,w,next;
14 } e[M];
15 struct cmp{
16     bool operator()(int a,int b){
17         return dis[a]>dis[b];
18     }
19 };
20 priority_queue< int , vector<int> , cmp > q;
21 inline int read(){
22     int x=0; char c=getchar();
23     while(c<'0'||c>'9') c=getchar();
24     while('0'<=c&&c<='9') { x=(x<<3)+(x<<1)+c-'0'; c=getchar(); }
25     return x;
26 }
27 inline void add(int x,int y,int w){
28     e[++tot].to=y;
29     e[tot].w=w;
30     e[tot].next=Head[x];
31     Head[x]=tot;
32 }
33 int prim(int St){
34     int sum=0;
35     for(int i=1;i<=n;i++){
36         dis[i]=1000000;
37         dep[i]=14; vis[i]=0;
38     }
39     dis[St]=dep[St]=0;
40     q.push(St);
41     while(!q.empty()){
42         int u=q.top(); q.pop();
43         if(vis[u]) continue;
44         vis[u]=1; sum+=dis[u];
45         for(int i=Head[u];i;i=e[i].next){
46             int v=e[i].to;
47              if(dis[v]>(dep[u]+1)*e[i].w){
48                 dep[v]=dep[u]+1;
49                 dis[v]=dep[v]*e[i].w;
50             }
51             q.push(v);
52         }
53     }
54     return sum;
55 }
56 int main()
57 {
58     scanf("%d%d",&n,&m);
59     int x,y,w;
60     for(int i=1;i<=m;i++){
61         x=read(); y=read(); w=read();
62         add(x,y,w); add(y,x,w);
63     }
64     ans=INF;
65     for(int i=1;i<=n;i++)
66      ans=min(ans,prim(i));
67     printf("%d\n",ans);
68     return 0;
69 }

 

然后看到题解里状压DP、模拟退火什么玩意的。。

模拟退火我是不会的

不过随机化什么的好像可以骗一下分

于是将代码改了一点

 

#include<iostream>
#include<cstring>
#include<cstdlib>
#include<cstdio>
#include<queue>
using namespace std;
#define N 15
#define M 2000
#define INF 0x3f3f3f3f
int n,m,dis[N],dep[N],ans;
int Head[N],tot;
bool vis[N];
struct NODE{
    int to,w,next;
} e[M];
struct cmp{
    bool operator()(int a,int b){
        return dis[a]+rand()>dis[b]+rand();  //非常low的随机化
    }
};
priority_queue< int , vector<int> , cmp > q;
inline int read(){
    int x=0; char c=getchar();
    while(c<'0'||c>'9') c=getchar();
    while('0'<=c&&c<='9') { x=(x<<3)+(x<<1)+c-'0'; c=getchar(); }
    return x;
}
inline void add(int x,int y,int w){
    e[++tot].to=y;
    e[tot].w=w;
    e[tot].next=Head[x];
    Head[x]=tot;
}
int prim(int St){
    int sum=0;
    for(int i=1;i<=n;i++){
        dis[i]=1000000;
        dep[i]=14; vis[i]=0;
    }
    dis[St]=dep[St]=0;
    q.push(St);
    while(!q.empty()){
        int u=q.top(); q.pop();
        if(vis[u]) continue;
        vis[u]=1; sum+=dis[u];
        for(int i=Head[u];i;i=e[i].next){
            int v=e[i].to;
            if(vis[v]) continue;
             if(dis[v]>(dep[u]+1)*e[i].w){
                dep[v]=dep[u]+1;
                dis[v]=dep[v]*e[i].w;
            }
            q.push(v);
        }
    }
    return sum;
}
int main()
{
    srand(19260817);
    scanf("%d%d",&n,&m);
    int x,y,w;
    for(int i=1;i<=m;i++){
        x=read(); y=read(); w=read();
        add(x,y,w); add(y,x,w);
    }
    ans=INF;
    int g=200;
    while(g--){
        srand(rand());
        for(int i=1;i<=n;i++)
         ans=min(ans,prim(i));
    }
    printf("%d\n",ans);
    return 0;
}

 

很迷的是上面代码的复杂度巨大

然后发现一个很严重的问题

邻接表就跟吔了shi一样

我们将邻接表改成邻接矩阵,

又改了一下随机化的方式

#include<iostream>
#include<cstring>
#include<cstdlib>
#include<cstdio>
#include<queue>
using namespace std;
const int MAXN=15,MAXM=2010;
const int INF=0x3f3f3f3f;
int n,m,g[MAXN][MAXN];
int Head[MAXN],num;
struct NODE{
    int pos,cost;
};
struct cmp{
    bool operator ()(NODE a,NODE b){
        return a.cost>b.cost;
    }
};
priority_queue< NODE,vector<NODE>,cmp > que;
bool vis[MAXN];
NODE s[MAXM];
int cnt,dis[MAXN],tot[MAXN];
int prim(int S){
    int ans=0;
    memset(vis,0,sizeof(vis));
    memset(dis,0x3f,sizeof(dis));
    que.push(NODE{S,0});dis[S]=tot[S]=0;
    for(int i=1;i<=n;i++){
        cnt=0;
        while(!que.empty()&&(vis[que.top().pos]||rand()%(i+1)<1)){
            if(!vis[que.top().pos])
                s[++cnt]=que.top();
            que.pop();
        }
        int k;
        if(que.empty()) k=s[cnt].pos,cnt--; 
        else k=que.top().pos,que.pop();
        vis[k]=1;
        ans+=dis[k];
        if(ans>INF) return INF;
        for(int i=1;i<cnt;i++) que.push(s[i]);
        for(int i=1;i<=n;i++)
         if(g[k][i]<INF){
            if(dis[i]>(tot[k]+1)*g[k][i]){
                tot[i]=tot[k]+1;
                dis[i]=tot[i]*g[k][i];
            }
            que.push(NODE{i,dis[i]});
        }
    }
    return ans;
}
int main()
{
    memset(g,0x3f,sizeof(g));
    scanf("%d%d",&n,&m);
    int x,y,w;
    for(int i=1;i<=m;i++){
        scanf("%d%d%d",&x,&y,&w);
        if(w<g[x][y]) g[x][y]=g[y][x]=w;
    }
    int ans=INF;
    int t=500;
    while(t--)
        for(int i=1;i<=n;i++)
            ans=min(ans,prim(i));
    printf("%d\n",ans);
    return 0;
}  

以上做法都不大靠谱,大家还是状压DP吧(逃

posted @ 2018-07-11 20:54  yjk  阅读(173)  评论(0编辑  收藏  举报