題目html
題意:node
無向圖,給n個城市,n*n條邊,每條邊都有一個權值 表明修路的代價,其中有k個點有發電站,給出這k個點的編號,要每個城市都連到發電站,問最小的修路代價。ios
思路:ide
prim:把發電站之間e[i][j]都設置爲0,而後模板套進去就行。優化
krusl:把全部的發電站都先弄進一個並查集(作法比較機智,先拿其中一個發電站,把剩下的發電站分別與這個發電站找父節點,分別弄進並查集就行)。 而後按權值從小到大 排序,不是同一個並查集的就sum+=,再弄進並查集。spa
複雜度O(n*n).net
#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)3d
#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; }
參考博客code
複雜度O(mlogm)htm
#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)); }