蒟蒻萌新表示代码过了,如何优化

P3366 【模板】最小生成树

LiuChip_ssy @ 2021-09-01 21:13:19

#include<bits/stdc++.h>
using namespace std;
int fread()
{
    char ch=getchar();
    int x=0,flag=1;
    while(ch>'9'||ch<'0')
    {
        if(ch=='-') flag=-1;
        ch=getchar();
    }
    while(ch>='0'&&ch<='9')
    {
        x=x*10+ch-'0';
        ch=getchar();
    }
    return x*flag;
}//快读 
const int maxn=2e5+1;//最大边数 
struct node
{
    bool vis;//是否被访问 
    int dis;//到这个点的最小距离 
    int parent;//距离这个点距离最小的点 
    int linked;//这个点连接别的点的个数 
}num[maxn];//数字个数 
int n,m,dis1[5001][5001],start=INT_MAX;//n是点数,m是边数,dis1存储n到m的距离,start表示起点 
void init()//初始化 
{
    fill(dis1[0],dis1[0]+5001*5001,INT_MAX);//所有距离均为不可达 
    for(int i=0;i<maxn;i++)
    {
        num[i].vis=false;//所有点均未被访问 
        num[i].dis=INT_MAX;//所有最大距离均为不可达 
        num[i].parent=-1;//所有的上一个距离最短的连接点均为-1 
        num[i].linked=0;//所有点的连接数均为0 
    }
    return;
}
int cnt=0,sum=0;//最小总边权 
void prim(int x)//更新 
{

    for(int i=start+1;(!(x<start)&&!(x>=start+n)&&!(num[x].linked==0))
    &&i<start+n;i++)//判断i这个点是否在图内
    {
        if(num[i].vis) continue;//判断这个点是否被访问 
        if(dis1[x][i]<num[i].dis)//更新最短距离 
        {
            num[i].dis=dis1[x][i];
            num[i].parent=x;
        }
    }
    int nxt=INT_MAX;//下一次递归的点 
    int fa=INT_MAX;//距离下一次递归的点距离最近的点 
    int minx=INT_MAX;//最短的距离 
    for(int j=start;j<start+n;j++)
    {
        if(num[j].vis) continue;//判断是否已被访问 
        if(num[j].dis<minx)//找到最短距离 
        {
            minx=num[j].dis;//更新最短距离 
            nxt=j;//更新下一次递归的(也就是作为起点的)点 
            fa=num[j].parent;//更新fa 
        }
    }
    if(minx!=INT_MAX) 
    {
        cnt+=minx;
        sum++;
    }//更新最小总边权 
    else return;//如果不可达就返回 
    num[start].vis=true;//起点访问记录改为true 
    num[nxt].vis=true;//下一个点访问记录改为true 
    prim(nxt);//递归 
    return;
}
int main()
{
    n=fread(),m=fread();//快读输入点和边的个数 
    init();//初始化 
    for(int i=1;i<=m;i++)
    {
        int temp1=fread(),temp2=fread(),temp3=fread();//读入边 
        start=min(start,min(temp1,temp2));//找到编号最小的点 
        dis1[temp1][temp2]=dis1[temp2][temp1]=min(dis1[temp1][temp2],temp3);//添加边 
        num[temp1].linked++;//连接数+1 
        num[temp2].linked++;//连接数+1 
    }
    prim(start);//从起点开始递归 
    if(sum<n-1)//如果边数小于n-1则不能生成最小生成树,输出orz 
    {
        printf("orz");
        return 0;
    }
    printf("%d",cnt);//否则输出最小总边权 
    return 0;//结束 
}

我这里写的是Prim算法,代码的注释也写的很清楚了,但是时间特别长(1.89s),空间也特别大(99.46MB)。可以问下如何优化吗?


by LiuChip_ssy @ 2021-09-01 21:16:02

当时想的是:如果他周边的距离都是不可达或者有可达的点但是点都被访问了,这种情况下来判断点是否在图内。但是无论如何我也没有办法实现,所以就加了那个linked。而且我的prim模板是自己摸索出来的,比大神们的写的要长的多。


by KAMIYA_KINA @ 2021-09-01 21:19:59

你以后考场上不会想写 prim 的,相信我。

能写 kruscal 就写 kruscal。


by LiuChip_ssy @ 2021-09-02 21:53:48

@KAMIYA_KINA 哦哦哦好的,感谢大佬指导~


|