Prim求助

P3366 【模板】最小生成树

@[wu13115899522](/user/442963) wbh怎么prim都会了,我都不会
by Xjin @ 2022-09-28 19:27:39


啊这
by wu13115899522 @ 2022-09-28 19:31:50


@[wu13115899522](/user/442963) 你的cost[x][y]=cost[y][x]=z 是不是应该改成cost[x][y]=cost[y][x]=min(z,cost[x][y]);别的未知
by Xjin @ 2022-09-28 21:50:04


@[wu13115899522](/user/442963) 干嘛不打克鲁斯卡尔
by Xjin @ 2022-09-28 21:50:35


@[wu13115899522](/user/442963) 我Kruskal都过了 ```cpp #include<bits/stdc++.h> using namespace std; int n,m,fa[5005],ans,sum; struct data{ int x,y,z; bool operator < (const data b) const { return z<b.z; } }eadg[400005]; int read(){ char ch=getchar(); int x=0,f=1; while(ch<'0'||ch>'9')ch=getchar(); while(ch>='0'&&ch<='9')x=(x<<3)+(x<<1)+(ch^48),ch=getchar(); return x*f; } int getfa(int x){ if(fa[x]==x)return x; return fa[x]=getfa(fa[x]); } signed main(){ n=read();m=read(); for(int i=1;i<=n;i++)fa[i]=i; for(int i=1;i<=m;i++){eadg[i].x=read();eadg[i].y=read();eadg[i].z=read();} sort(eadg+1,eadg+m+1); for(int i=1;i<=m;i++){ int fx=getfa(eadg[i].x); int fy=getfa(eadg[i].y); if(fx!=fy){ fa[fx]=fy; ans+=eadg[i].z; sum++; } if(sum==n-1)break; } if(sum!=n-1){ cout<<"orz"; return 0; } printf("%d",ans); return 0; } ``` 不必prim好打???
by Xjin @ 2022-09-28 22:43:27


@[wu13115899522](/user/442963) 《prim》 1. `dis[j]=dis[mj]+cost[mj][j];`你认真的?并且更新还判vis您是打算只更新一次是吧。这个prim跟我用rand随机输出一个答案没什么不同。建议重学prim捏 2. 你的写法是以1为起点,但你却没有标记`vis[1]=1` 3. 邻接表的确不用判重边,但是邻接矩阵不需要判重边?? 4. 这个错查了很久。你的 $ans$ 初始值是 $2147483647$,但是 $dis$ 数组初始值是`memset`下的 $63$。前者肯定比后者大,那么即使两个点之间没有连边,也会强制连起来。我的做法是把所有初始化改成了0x3f3f3f3f。 代码如下: ```cpp #include<bits/stdc++.h> using namespace std; int cost[5005][5005]; int dis[5005]; int n,m; bool vis[5005]; int ans=0; void prim(){ dis[1]=0; vis[1]=1;//4 对1的特殊vis处理 for(int i=2;i<=n;i++){ dis[i]=cost[1][i]; } for(int i=1;i<n;i++){ int minp=0x3f3f3f3f,mj=-1;//3.0x3f统一 for(int j=2;j<=n;j++){ if(minp>dis[j]&&!vis[j]){ minp=dis[j]; mj=j; } } if(minp==0x3f3f3f3f){ cout<<"orz"; exit(0); } // cout<<minp<<endl; ans+=minp; vis[mj]=true; for(int j=2;j<=n;j++){ if(dis[j]>cost[mj][j]){//1.vis不必要,更新过程建议重学prim捏 dis[j]=cost[mj][j]; } } } return ; } int main(){ scanf("%d%d",&n,&m); memset(cost,0x3f3f3f3f,sizeof(cost)); memset(dis,0x3f3f3f3f,sizeof(dis)); for(int i=1;i<=m;i++){ int x,y,z; scanf("%d%d%d",&x,&y,&z); cost[x][y]=cost[y][x]=min(cost[x][y],z);//2 重边 } for(int i=1;i<=n;i++){ cost[i][i]=0; } prim(); cout<<ans; return 0; } ```
by xs_siqi @ 2022-09-28 23:50:45


@[xs_siqi](/user/401088) 1.更新判vis对结果没影响,建议~~您也去重学Prim~~ 2.初始的1不需要vis[1]=true也是同理。证明使用构造方式+反证法+贪心解决。 3.~~至少这个算法对于同一输入多次运行只会输出一个答案,这点比rand“好”~~ @[wu13115899522](/user/442963) 1.memset初始化63只有10亿左右,显然小于2147483647,必然更新,下次开到1e9就可以了。(警示后人) 2.最小值一定是最后一次更新的吗?建议打程序前先激活你的大脑。 3.邻接矩阵不用min,题目保证两点只有一条边吗? 4.你wbh,Prim模板都不会打,你怎么学,噢? @[wzxj](/user/451100) 1.不要五十步笑百步,你也不会打Prim; 2.其实Kruskal的最坏复杂度会比Prim高,所以还是建议去学Prim。
by J2a0m0e8s @ 2022-09-29 17:44:00


az,没认真看 Prim的最小值是到连通块的最小值,不是到起点,这点与Dijkstra不同。@[wu13115899522](/user/442963)
by J2a0m0e8s @ 2022-09-29 19:50:25


@[J2a0m0e8s](/user/437368) 我没有取笑他啊???我不是说我也不会吗???
by Xjin @ 2022-09-29 21:05:10


@[J2a0m0e8s](/user/437368) vis貌似的确是判不判无所谓。 vis1没标记是因为数据比较水。
by xs_siqi @ 2022-09-29 21:20:22


| 下一页