ACM比赛模板.docx
《ACM比赛模板.docx》由会员分享,可在线阅读,更多相关《ACM比赛模板.docx(91页珍藏版)》请在冰豆网上搜索。
![ACM比赛模板.docx](https://file1.bdocx.com/fileroot1/2022-10/11/b467250b-c6c0-4947-85d7-4072c4d6683f/b467250b-c6c0-4947-85d7-4072c4d6683f1.gif)
ACM比赛模板
1.最小生成树
要连通n个城市需要n-1条边线路。
可以把边上的权值解释为线路的造价。
则最小生成树表示使其造价最小的生成树。
prim算法(矩阵形式):
#defineinf0x3f3f3f3f
intprim(intn,intsta)//n表示有n个顶点,sta表从sta这个顶点出发生成最小生成树
{
intmark[M],dis[M];
inti,sum=0; //sum是总的最小生成树边权值
for(i=0;i {
dis[i]=mat[sta][i];
mark[i]=0;
}
mark[sta]=1; //sta这个顶点加入最小生成树中
for(i=1;i { //只有n-1条边
intmin=inf; //inf表无穷大
for(j=0;j if(!
mark[j]&&dis[j] min=dis[j],flag=j;
mark[flag]=1; //把该顶点加入最小生成树中
sum+=dis[flag]; //sum加上其边权值
for(j=0;j if(dis[j]>mat[flag][j])
dis[j]=mat[flag][j];
}
returnsum; //返回边权总和
}
prim算法(边表形式):
structEdge//frm为起点,to为终点,w为边权,nxt指向下一个顶点
{
//intfrm;
intto,w,nxt;
}edge[M];
intvis[M],head[M],dis[M];
voidaddedge(intcu,intcv,intcw)//生成边的函数
{
//edge[e].frm=cu;
edge[e].to=cv;
edge[e].w=cw;
edge[e].nxt=head[cu];
head[cu]=e++;
//edge[e].frm=cv;
edge[e].to=cu;
edge[e].w=cw;
edge[e].nxt=head[cv];
head[cv]=e++;
}
intprim(intn,intsta)//n为顶点数量,sta为起点
{
intsum=0;
memset(dis,0x3f,sizeof(dis));
memset(vis,0,sizeof(vis));
for(i=head[sta];i!
=-1;i=edge[i].nxt)//遍历与sta点相连的所有顶点
{
intv=edge[i].to;
dis[v]=edge[i].w;
}
vis[sta]=1;//加入到最小生成树中
intm=n-1; //只生成n-1条边,所以循环n-1次
while(m--)
{
intmin=inf;
for(i=0;i if(!
vis[i]&&dis[i] flag=i,min=dis[i];
sum+=dis[flag];
vis[flag]=1;//加入到最小生成树中
for(i=head[flag];i!
=-1;i=edge[i].nxt)//更新与flag顶点相连的点的dis
{
intv=edge[i].to;
if(edge[i].w dis[v]=edge[i].w;
}
}
returnsum;//返回边权总和
}
intmain()
{
e=0; //记得初始化
memset(head,-1,sizeof(head));
scanf("%d%d%d",&a,&b,&w);
addedge(a,b,w);
.....
.....
prim(n,sta);
return0;
}
Kruskal算法:
structEdge
{
intv1,v2,w;
}edge[M],tree[M]; //w为v1顶点到v2顶点的边权
/*
intFind(intparent[],intu)//第1种写法
{
inttmp=u;
while(paren[tmp]!
=-1)
tmp=parent[tmp];
returntmp;
}
*/
intFind(intu) //第2种写法
{
if(u!
=parent[u])
parent[u]=Find(paren[u]);
returnparent[u];
}
boolcmp(Edgea,Edgeb)
{
returna.w}
intKruskal()//parent[]表示集合
{
intparent[M];
inti,j,sum,vf1,vf2;
sort(edge,edge+E,cmp);
// memset(parent,-1,sizeof(parent));//对应第1种并查集的初始化
for(i=0;i parent[i]=i;
sum=i=j=0;
while(i {
vf1=Find(parent,edge[i].v1); //找这两个点的祖先
vf2=Find(parent,edge[i].v2);
if(vf1!
=vf2)//若两个点的祖先不同,说明不在同一集合
{
parent[vf2]=vf1;//把vf2点加到vf1点的集合中
tree[j++]=edge[i];//把边加到tree[]数组中,这句题目没要求可忽略之
sum+=edge[i].w; //sum加上其边权
}
i++;
}
returnsum;
}
最小生成树--Kruskal算法:
运用数组存点与边的权值
#include
#include
#include
#defineN150
usingnamespacestd;
intm,n,u[N],v[N],w[N],p[N],r[N];
intcmp(constinti,constintj){returnw[i]intfind(intx){returnp[x]==x?
x:
p[x]=find(p[x]);}
intkruskal()
{
intcou=0,x,y,i,ans=0;
for(i=0;ifor(i=0;isort(r,r+m,cmp);
for(i=0;i{
inte=r[i];x=find(u[e]);y=find(v[e]);
if(x!
=y){ans+=w[e];p[x]=y;cou++;}
}
if(coureturnans;
}
intmain()
{
inti,ans;
while(scanf("%d%d",&m,&n)!
=EOF&&m)
{
for(i=0;i{
scanf("%d%d%d",&u[i],&v[i],&w[i]);
}
ans=kruskal();
if(ans)printf("%d\n",ans);
elseprintf("?
\n",ans);
}
return0;
}
2.最短路算法
①DIJK
C++代码
1.#define inf 0x3fffffff
2.#define M 105
3.
4.int dist[M], map[M][M], n;
5.bool mark[M];
6.
7.void init ()
8.{
9. int i, j;
10. for (i = 1; i <= n; i++) //i==j的时候也可以初始化为0,只是有时候不合适
11. for (j = 1; j <= n; j++)
12. map[i][j] = inf;
13.}
14.
15.void dijk (int u)
16.{
17. int i, j, mins, v;
18. for (i = 1; i <= n; i++)
19. {
20. dist[i] = map[u][i];
21. mark[i] = false;
22. }
23. mark[u] = true;
24. dist[u] = 0; //既然上面的map当i==j时不是0,就要这句
25. while
(1)
26. {
27. mins = inf;
28. for (j = 1; j <= n; j++)
29. if (!
mark[j] && dist[j] < mins)
30.