Electrification Plan 最小生成树(prim+krusl+堆优化prim)
题意:
无向图,给n个城市,n*n条边,每条边都有一个权值 代表修路的代价,其中有k个点有发电站,给出这k个点的编号,要每一个城市都连到发电站,问最小的修路代价。
思路:
prim:把发电站之间e[i][j]都设置为0,然后模板套进去就行。
krusl:把所有的发电站都先弄进一个并查集(做法比较机智,先拿其中一个发电站,把剩下的发电站分别与这个发电站找父节点,分别弄进并查集就行)。 然后按权值从小到大 排序,不是同一个并查集的就sum+=,再弄进并查集。
复杂度O(n*n)
#include<iostream> #include<cstdio> #include <cctype> #include<algorithm> #include<cstring> #include<cmath> #include<string> #include<cmath> #include<set> #include<vector> #include<stack> #include<queue> #include<map> using namespace std; #define ll long long #define mem(a,x) memset(a,x,sizeof(a)) #define se second #define fi first const ll mod=998244353; const int INF= 0x3f3f3f3f; const int N=2e5+5; int n,m; int e[105][105]; int b[105],dis[105],vis[105]; void prim() { for(int i=1;i<=n;i++) { vis[i]=0; dis[i]=e[1][i]; } int u,minn,sum=0; vis[1]=1; for(int i=1;i<n;i++) { minn=INF; for(int j=1;j<=n;j++) { if(!vis[j] && minn>dis[j]) { u=j; minn=dis[j]; } } vis[u]=1; sum+=minn; for(int j=1;j<=n;j++) { if(!vis[j] && e[u][j]<dis[j]) dis[j]=e[u][j]; } } printf("%d\n",sum); } int main() { cin>>n>>m; for(int i=1;i<=n;i++) for(int j=1;j<=n;j++) if(i==j) e[i][j]=0; else e[i][j]=INF; for(int i=1;i<=m;i++) scanf("%d",&b[i]); for(int i=1;i<=n;i++){ for(int j=1;j<=n;j++){ scanf("%d",&e[i][j]); } } for(int i=1;i<=m;i++) for(int j=1;j<=m;j++) e[b[i]][b[j]]=0; prim(); }
复杂度O(mlogm)
#include<iostream> #include<cstdio> #include <cctype> #include<algorithm> #include<cstring> #include<cmath> #include<string> #include<cmath> #include<set> #include<vector> #include<stack> #include<queue> #include<map> using namespace std; #define ll long long #define mem(a,x) memset(a,x,sizeof(a)) #define se second #define fi first const ll mod=998244353; const int INF= 0x3f3f3f3f; const int N=2e5+5; int f[N],n,m; struct edge { int u,v,w; }e[N]; bool cmp(edge x,edge y) { return x.w<y.w; } int getf(int x) { if(x!=f[x]) f[x]=getf(f[x]); return f[x]; } int krusl(int num) { int fa,fb,sum=0,cnt=0; for(int i=1;i<=num;i++) { fa=getf(e[i].u); fb=getf(e[i].v); if(fa!=fb) { f[fa]=fb; sum+=e[i].w; cnt++; } if(cnt==n-m) break; } return sum; } int main() { cin>>n>>m; for(int i=0;i<=n;i++) f[i]=i; int q; cin>>q; //拿q与其他所有的发电站都连接起来 for(int i=2;i<=m;i++) { int fa,fb,a; cin>>a; fa=getf(a); fb=getf(q); if(fa!=fb) f[fa]=fb; } int cnt=0; for(int i=1;i<=n;i++) { for(int j=1;j<=n;j++) { e[++cnt].u=i; e[cnt].v=j; scanf("%d",&e[cnt].w); } } sort(e+1,e+1+cnt,cmp); cout<<krusl(cnt)<<endl; }
复杂度O(mlogm)
#include<iostream> #include<cstdio> #include <cctype> #include<algorithm> #include<cstring> #include<cmath> #include<string> #include<cmath> #include<set> #include<vector> #include<stack> #include<queue> #include<map> using namespace std; #define ll long long #define mem(a,x) memset(a,x,sizeof(a)) #define se second #define fi first const ll mod=998244353; const int INF= 0x3f3f3f3f; const int N=2e5+5; int n,m; int vis[N]; struct edge { int u,v,w; bool operator<(const edge &r)const{ //priority_queue中用 return r.w<w; } edge(int _v,int _w):v(_v),w(_w){} //vector中用 }; vector<edge> ve[N]; void prim() { priority_queue<edge> q; for(int i=0;i<ve[1].size();i++) q.push(ve[1][i]); int cnt=n-1,sum=0; vis[1]=1; while(!q.empty() && cnt) { edge cur=q.top(); q.pop(); while(vis[cur.v]) { cur=q.top(); q.pop(); } sum+=cur.w; vis[cur.v]=1; for(int i=0;i<ve[cur.v].size();i++) { if(!vis[ ve[cur.v][i].v ] ) q.push(ve[cur.v][i]); } cnt--; } printf("%d\n",sum); } int main() { int u,v,w; cin>>n>>m; for(int i=1;i<=m;i++) { scanf("%d%d%d",&u,&v,&w); ve[u].push_back(edge(v,w)); ve[v].push_back(edge(u,w)); } prim(); }
题意:
毒气炸弹需要 k 种不同类型元素构成,Applese一共有 n 瓶含有这些元素的试剂。 已知元素混合遵循 m 条规律,每一条规律都可以用 "x y c" 描述。表示将第 x 瓶试剂混入第 y 瓶试剂或者把第 y 瓶试剂混入第 x 瓶试剂,需要消耗 c 的脑力。特别地,除了这 m 条规律外,Applese 可以将任意两瓶相同元素的试剂混合,且不需要消耗脑力。Applese 想要配出毒气炸弹,就需要使 S 中含有 这 k 种元素。它想知道自己最少花费多少脑力可以把毒气炸弹做出来。
思路:
和上面题目类似。把所有相同的加入同一个并查集。
#include<iostream> #include<cstdio> #include <cctype> #include<algorithm> #include<cstring> #include<cmath> #include<string> #include<cmath> #include<set> #include<vector> #include<stack> #include<queue> #include<map> using namespace std; #define ll long long #define mem(a,x) memset(a,x,sizeof(a)) #define se second #define fi first const ll mod=998244353; const int INF= 0x3f3f3f3f; const int N=2e5+5; int f[N],n,m,k; struct edge { int u,v,w; }e[N]; struct node { int pp, vv; }a[N]; bool cmp(edge x,edge y) { return x.w<y.w; } bool cmp2(node x,node y) { return x.vv<y.vv; } int getf(int x) { if(x!=f[x]) f[x]=getf(f[x]); return f[x]; } ll krusl(int num) { int fa,fb,cnt=0; ll sum=0; for(int i=1;i<=num;i++) { fa=getf(e[i].u); fb=getf(e[i].v); if(fa!=fb) { f[fa]=fb; sum+=1LL*e[i].w; cnt++; } if(cnt==k-1) break; } if(cnt!=k-1) return -1; else return sum; } int main() { cin>>n>>m>>k; for(int i=0;i<=n;i++) f[i]=i; for(int i=1;i<=n;i++) scanf("%d",&a[i].vv),a[i].pp=i; sort(a+1,a+1+n,cmp2); int q; int fa,fb; int j=1; for(int i=1;i<=k;i++) { if(a[j].vv ==i) { q=a[j].pp; j++; while(a[j].vv==i) { fa=getf(a[j].pp); fb=getf(q); if(fa!=fb) f[fa]=fb; j++; } } } for(int i=1;i<=m;i++) { scanf("%d%d%d",&e[i].u,&e[i].v,&e[i].w); } sort(e+1,e+1+m,cmp); printf("%lld\n",krusl(m)); }