啦啦啦啦啦

prime + 优先队列优化+ 前向星+贪心

1.首先你要看出这个是个最小生成树,题目描述的可能不太好,还请多多包涵(看不懂就看原题吧)

2,既然是最小生成树,无非不过prime和kruskal,这里题目固定起点从1出发,明显用prime舒服点。

3,几个卡的地方 :
①不能直接套最小生成树,一个点可以被多个点到达,所以你要考虑先走那条边好,而且只是 简单的先连最短的边的点是不对的
啦啦啦啦啦

对于prime算法假设起点是A,那么刚开始A,就是一颗树,如果只是简单的把到树最短的边连起来,那么会出出现将这ABCD,4个点连起来要消耗13的能源,但其实更短的是10。
那这么放心的把边连接起来?

这里要利用下题目的条件,只能从维度高的点到维低的点,所以每次贪心的把优先队列中维度最高的点先出队,因为队列中没有别的点比这个最高点维度更高,所以该点只能通过已经有比他维度更高的点达到,所以可以放心的把到这个点的边加上,不用担心它的边的长短,因为这个点一定要这样到达。所以对优先队列排序 以维度高低优先,如果维度一样,按边短的优先。

②如何建图:
N<105,M<105所以邻接矩阵建图不可取,那就只能邻接表,但这个指针很麻烦,所以可以用链式前向星(https://blog.csdn.net/acdreamers/article/details/16902023),然后建图的时候要根据维度判断哪个点是起点,哪个是终点,同维度双向边,否则单向边,这里卡了下内存,所以空间刚好够用就行,别开太大

Prime+优先队列 时间复杂度 在nlogn + m所以可行

我的板子prime板子

#include <bits/stdc++.h>//时间复杂度 nlogn + m 堆中最多n个点 每次堆排序(logn) 最多入堆n次
using namespace std;    //适用于稠密图
const int MAX =100000;

struct point{
    int to,w,next;
    bool operator < (const point &a)   const{
        return w > a.w;
    }
};
point edge[MAX];
bool vis[MAX];
int head[MAX];
int dis[MAX];//到树的距离
int cnt = 0;
int c,m,n;
void addedage(int x,int y,int z){
    edge[++cnt].to = y;
    edge[cnt].w = z;
    edge[cnt].next = head[x];
    head[x] = cnt;
}
priority_queue<point> q;
void prim(void){
    int ans = 0,ct = 0;//记录路径和,生成树拥有点数
    point t;
    t.to = 1;
    t.w = 0;
    dis[0] = 0;//起点到树的距离为0 
    q.push(t);
    
    while(!q.empty()){
        t = q.top();
        q.pop();
        if(vis[t.to])//一个点可能多次入队了
            continue;
        vis[t.to] = true;
        ans+=t.w;//求生成树路径和
      
        if(++ct == n){//判断是否已经 n个点相连,加上了n-1条边
            return;
        }

        for(int i = head[t.to];~i;i = edge[i].next){
            int u = edge[i].to;
            if(!vis[u] && dis[u] > edge[i].w){//边不在树上并且边更短
                dis[u] = edge[i].w;
                t.to = u;
                t.w = dis[u];
                q.push(t);
            }
        }
    }
}

int main(){
    
    while(cin >> c >> m >> n){
        int x,y,z;
        cnt = 0;
        memset(head,-1,sizeof(head));
        memset(vis,0,sizeof(vis));
        memset(dis,0x3f,sizeof(dis));//注意边的范围
        for(int i = 0;i < m;i++){
            cin >> x >> y >> z;
            addedage(x,y,z);
            addedage(y,x,z);
        }
        prim();
    }
    
    //system("pause");
    return 0;
}

AC代码

#include<bits/stdc++.h>
using namespace std;
const int MAXE = 200020;
const int MAXV = 100020;
typedef long long ll;

ll dist[MAXV];
bool vis[MAXV];
int head[MAXV];
int vertex[MAXV];
struct point{
    ll to,w,next;
    
};
bool operator < (point ty1,point ty2){
    if( vertex[ty1.to] < vertex[ty2.to]){
            return true;
        }else if( vertex[ty1.to] > vertex[ty2.to]){
            return false;
        }else{
            return ty1.w > ty2.w;
        }
}
point edge[MAXE];
int cnt = 0;
ll n,m;
priority_queue<point> q;
void addedage(int x,int y,int z){
    edge[++cnt].to = y;
    edge[cnt].w = z;
    edge[cnt].next = head[x];
    head[x] = cnt;
}
void prime(int s){
    ll ans = 0,ct = 0;
    
    dist[s] =0;
    point t;
    t.to = s;
    t.w = 0;
    q.push(t);
    
    while(!q.empty()){
        t = q.top();
        q.pop();
        
        if(vis[t.to])
            continue;
        vis[t.to] = true;
        ans+=t.w;
        
        if(++ct == n)
            break;
        for(int i = head[t.to];~i;i = edge[i].next){
            ll u = edge[i].to;
            //cout << u << " " << vis[u] << " " << dist[u] << " " << edge[i].w <<endl;
            if(!vis[u] && dist[u] > edge[i].w){
            
                dist[u] = edge[i].w;
                t.to = u;
                t.w = dist[u];
                q.push(t);
                 //cout << u << endl;
            }
        }
        
    }
   
    printf("%lld %lld\n",ct,ans);
    priority_queue<point> q1;//清空队列
    q = q1;
    return ;
    
}

int main(){
//  freopen("C:\\Users\\86130\\Desktop\\code\\problem\\1.in","r",stdin);
//  freopen("C:\\Users\\86130\\Desktop\\code\\problem\\1.out","w",stdout);
    while(scanf("%lld %lld",&n,&m)!=EOF){
    //  scanf("%lld %lld",&n,&m);
        memset(head,-1,sizeof(head));
        memset(dist,0x3f,sizeof(dist));
        memset(vis,0,sizeof(vis));
        memset(vertex,-1,sizeof(vertex));
        cnt = 0;
        
       
        for(int i = 1;i <= n;i++)
            scanf("%lld",&vertex[i]);
        ll x,y,z;
        for(int j = 0;j < m;j++){
            scanf("%lld %lld %lld",&x,&y,&z);
            if(vertex[x] > vertex[y])
                addedage(x,y,z);
            else if(vertex[x] < vertex[y])
                addedage(y,x,z);
            else{
                addedage(x,y,z);
                addedage(y,x,z);
            }
        }
        
        prime(1);
    }
   // system("pause");
    return 0;
}

上一篇:CodeForces-682C(DFS,树,思维)


下一篇:ANSYS ICEM CFD三维结构网格生成实例——汽车外流