畅通工程2(Prim邻接写法+kru)
prim其实很简单的(
事实上改了一晚上)丢人)
Prim思想
类似dij,每次选取离生成树(已知)最近的点,遍历该点的所有出边,更新dis.
prim中的dis数组含义区别于dij求最短路的算法.
#include<bits/stdc++.h>
#define ll long long
using namespace std;
const int INF=999999999;
int T,n,m,tot,cnt,num=1,u,v,w; char c; int ans,sum; bool flag=0;
struct E{
int fr,to,val,next;
}e[105*105];
int head[105],dis[105]; bool vis[105];
int main(){
while(~scanf("%d %d",&m,&n)){
if(m==0) return 0; //结束
sum=0;cnt=0;num=1;flag=0;
for(int i=1;i<=n;i++){
dis[i]=INF;
vis[i]=0;
}memset(head,-1,sizeof(head)); //初始化
for(int i=1;i<=m;i++){//读入每条边
scanf("%d%d%d",&u,&v,&w);//默认构造函数
e[num]={u,v,w,head[u]};
head[u]=num++; //u的最后一个出边的序号num;
e[num]={v,u,w,head[v]}; //加入反边
head[v]=num++;
}
dis[1]=0; vis[1]=1;//从 1->n开始构造生成树
for(int i=head[1];i!=-1;i=e[i].next){//遍历 1 的所有出边
if(dis[e[i].to]>e[i].val) // 更新已生成树到其他未进入生成树点的距离
dis[e[i].to]=e[i].val;
}
int mp=-1;
for(int i=1;i<=n;i++){
int minn=INF;
for(int j=2;j<=n;j++){// 1 已被标记 所以从 2 开始
if(vis[j]==0&&dis[j]<minn){ // 如果未入树
minn=dis[j];//
mp=j;//最近的点的标号
}//找到离已生成树最近的点
}
if(mp==-1){
flag=1;
break;
}//未找到
vis[mp]=1;//标记该点入树
for(int k=head[mp];k!=-1;k=e[k].next){//遍历mp的所有出边,更新dis
if(vis[e[k].to]==0&&dis[e[k].to]>e[k].val){
dis[e[k].to]=e[k].val;
}
}
}
for(int i=1;i<=n;i++){//dis数组全部更新完
if(dis[i]!=INF)
sum+=dis[i];
else{
flag=1;
break;
}
}
if(flag) puts("?");
else printf("%d\n",sum);
}
return 0;
}
正经起来了
代码还是有一些问题的(不够完美).我是追求完美的人(挨打).
比如:最后求最小生成树的权值时,是不需要判断. 理由是 在进行n轮的更新dis数组(即MST 拽下英文 )过程中有跳出循环的语句了(见注释未找到).
前天写了kru的代码(吹爆kru) 痴呆型选手的福音(流口水)
kru思想
按权值升序,遍历每一条边,若以联通,则不需要,否则是该边的两点联通.
联通操作使用并查集(吹爆并查集).
总的来说,就是,并查集判联通+贪心选边.不会证明(痴呆型选手不需要会证明)
#include<bits/stdc++.h>
#define ll long long
using namespace std;
const int mod=(int)(1e9)+7;
const int INF=99999999;
int T,n,m,tot,cnt,num=1; char c;ll sum;bool flag;
int pre[125];
struct edge{
int fr,to,val;
}e[10050];
bool cmp(edge s1,edge s2){
return s1.val<s2.val;
}
int find(int x){
int up=x;
while(up!=pre[up]){
up=pre[up];
}
int k=x,j;
while(k!=up){
j=pre[k];
pre[k]=up;
k=j;
}
return up;
}
bool merge(int x,int y){
int fx=find(x),fy=find(y);
if(fx!=fy){
pre[fx]=fy;
return 1;
}
return 0;
}
int main(){
while(~scanf("%d %d",&m,&n)){
if(m==0) return 0;
for(int i=1;i<=n;i++) pre[i]=i;
sum=cnt=0;
for(int i=1;i<=m;i++) scanf("%d %d %d",&e[i].fr,&e[i].to,&e[i].val);
sort(e+1,e+m+1,cmp);
for(int i=1;i<=m;i++){
if(merge(e[i].fr,e[i].to)){
sum+=e[i].val;
}
if(cnt==n-1){
break;
}
}
for(int i=1;i<=n;i++){
if(pre[i]==i){
cnt++;
}
}
// for(int i=1;i<=n;i++) printf("%d ",pre[i]);
// cout<<endl;
// cout<<cnt<<endl;
if(cnt>=2) puts("?");
else
printf("%lld\n",sum);
}
return 0;
}
第一篇正经题解,纪念一下.以示我会写裸的MST了.自吹爆己~~
纪念完了
Dmymax_ly
2019/3/13 00:07
目标是徐州邀请赛,永远记得.