活动 - AcWing
参考:《算法竞赛进阶指南》-lyd
目录
一、基础算法
二、
1.最短网络(prim板子)
2.局域网(kruskal板子)
3.繁忙的都市
4.1143. 联络员
5.连接格点(预处理)
一、基础算法
prim和kruskal算法。可参考之前发过的文章。
二、
1.最短网络(prim板子)
把所有农场连接起来的最短长度方案。
即最小生成树。
给的数据是邻接矩阵,所以用prim算法。
#include<iostream>
#include<algorithm>
#include<cstring>
using namespace std;
const int N =110;
int n;
int w[N][N];
int dist[N];
bool st[N];
int prim()
{
memset(dist,0x3f,sizeof dist);
dist[1]=0;
int res=0;
for(int i=0;i<n;i++)
{
int t=-1;
for(int j=1;j<=n;j++)
if(!st[j]&&(t==-1||dist[j]<dist[t]))
t=j;
res+=dist[t];
st[t]=true;
for(int j=1;j<=n;j++)
dist[j]=min(dist[j],w[t][j]);
}
return res;
}
int main()
{
cin>>n;
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
cin>>w[i][j];
cout<<prim();
return 0;
}
作者:yankai
链接:https://www.acwing.com/activity/content/code/content/4405659/
来源:AcWing
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
2.局域网(kruskal板子)
去边不能破坏连通,所以需要维护连通块。
处理连通块可以用并查集和dfs预处理。这里用并查集方便。
因为所有边的权值总和是不变的,所以我们算出来保留的边的权值总和越小,删掉的边的权值总和越大。
因此跑kruskal,从小到大遍历边,如果不连通,就把这条边保留用作连通,如果已经连通,就带表这条边可以去掉。
#include<iostream>
#include<algorithm>
#include<cstring>
using namespace std;
const int N =110,M=210;
int n,m;
struct Edge{
int a,b,w;
bool operator <(const Edge& t)const
{
return w<t.w;
}
}e[M];
int p[N];
int res;
int find(int x)
{
if(p[x]!=x) p[x]=find(p[x]);
return p[x];
}
int main()
{
cin>>n>>m;
for(int i=1;i<=n;i++) p[i]=i;
for(int i=0;i<m;i++)
{
int a,b,c;
cin>>a>>b>>c;
e[i]={a,b,c};
}
sort(e,e+m);
for(int i=0;i<m;i++)
{
int a=find(e[i].a),b=find(e[i].b),w=e[i].w;
if(a!=b) p[a]=b;//不连通则选择该条边
else res+=w;//已连通则除去该条边
}
cout<<res;
return 0;
}
作者:yankai
链接:https://www.acwing.com/activity/content/code/content/4435790/
来源:AcWing
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
3.繁忙的都市
求最小生成树,并且输出最小生成树中最大的那条边。
#include<iostream>
#include<algorithm>
#include<cstring>
using namespace std;
const int N =310,M=8010;
int n,m;
struct Edge{
int a,b,w;
bool operator< (const Edge& t) const
{
return w<t.w;
}
}e[M];
int p[N];
int find(int x)
{
if(p[x]!=x) p[x]=find(p[x]);
return p[x];
}
int main()
{
cin>>n>>m;
for(int i=1;i<=n;i++) p[i]=i;
for(int i=0;i<m;i++)
{
int a,b,c;
cin>>a>>b>>c;
e[i]={a,b,c};
}
sort(e,e+m);
int res=-0x3f3f3f3f;
for(int i=0;i<m;i++)
{
int a=find(e[i].a),b=find(e[i].b),w=e[i].w;
if(a!=b) p[a]=b,res=max(res,w);
else continue;
}
cout<<n-1<<" "<<res;
}
作者:yankai
链接:https://www.acwing.com/activity/content/code/content/4435971/
来源:AcWing
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
4.1143. 联络员
把必选的选了,再跑kruskal。
#include<iostream>
#include<algorithm>
#include<cstring>
using namespace std;
const int N =2010,M=10010;
struct Edge{
int a,b,w;
bool operator<(const Edge& t) const
{
return w<t.w;
}
}e[M];
int n,m;
int p[N];
int find(int x)
{
if(p[x]!=x) p[x]=find(p[x]);
return p[x];
}
int main()
{
int res=0,k=0;
cin>>n>>m;
for(int i=1;i<=n;i++) p[i]=i;
for(int i=0;i<m;i++)
{
int type,a,b,c;
cin>>type>>a>>b>>c;
if(type==1)
{
p[find(a)]=find(b);
res+=c;
}
else e[k++]={a,b,c};
}
sort(e,e+k);
for(int i=0;i<k;i++)
{
int a=find(e[i].a),b=find(e[i].b),w=e[i].w;
if(a!=b)
{
p[a]=b;
res+=w;
}
else continue;
}
cout<<res;
}
作者:yankai
链接:https://www.acwing.com/activity/content/code/content/4436051/
来源:AcWing
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
5.连接格点(预处理)
暴力kruskal。先加纵向边,再加横向边来避免排序。
#include<iostream>
#include<algorithm>
#include<cstring>
using namespace std;
const int N =1010,M=N*N,K=2*M;
int n,m,k;
int ids[N][N];
struct Edge{
int a,b,w;
bool operator<(const Edge&t)const
{
return w<t.w;
}
}e[K];
int p[M];
int find(int x)
{
if(p[x]!=x) p[x]=find(p[x]);
return p[x];
}
void get_edges()
{
int dx[4] = {-1, 0, 1, 0}, dy[4] = {0, 1, 0, -1}, dw[4] = {1, 2, 1, 2};
for(int z=0;z<2;z++)
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)
for(int u=0;u<4;u++)
{
if(u%2==z)//先加纵向边 因此可以不用排序
{
int x=i+dx[u],y=j+dy[u],w=dw[u];
if (x&&x<=n&&y&&y<=m)
{
int a=ids[i][j],b=ids[x][y];
if(a<b) e[k++]={a,b,w};
}
}
}
}
int main()
{
cin>>n>>m;
for(int i =1,t=1;i<=n;i++)
for(int j=1;j<=m;j++,t++)
ids[i][j]=t;//坐标映射
for(int i=1;i<=n*m;i++) p[i]=i;
int x1,y1,x2,y2;
while(cin>>x1>>y1>>x2>>y2)
{
int a=ids[x1][y1],b=ids[x2][y2];
p[find(a)]=find(b);
}
get_edges();
int res=0;
for(int i=0;i<k;i++)
{
int a=find(e[i].a),b=find(e[i].b),w=e[i].w;
if(a!=b)
{
p[a]=b;
res+=w;
}
}
cout<<res;
return 0;
}