阿Q的密室

阿Q的密室
https://hszxoj.com/images/211012_w8wh3kPF4a.png

12.18.2021唯一一道A掉的题

分析题意可知,每组中的密室可以相互到达,则密室中至少有n-1条边,可以用最小生成树算法。

Prim

(关于全机房就我一个用Prim这件事)

Prim是基于点构造最小生成树,原图并不一定联通,可以视作若干个连通块,用vis数组标记已经在最小生成树里的点,如果vis[i]==0,跑一遍Prim(i),求出i所在连通块里的最小生成树,同时给这个连通块分一个组k--,如果k不够分则无解。

以diss记录最小生成树上的边(应该是所有边都有),如果k还有剩余就砍掉k条最长的边

Code

#include<bits/stdc++.h>
using namespace std;
const int maxn=1000000+5;
struct Edge{
    int from,to,next,dis;
}e[maxn*2];
struct node{
    int id,dis;
    bool operator<(node x)const{
        return x.dis<dis;
    }
};
int head[maxn],len,diss[maxn],d[maxn],Len;
long long MST[maxn],ans;
bool vis[maxn];
void Insert(int x,int y,int dis){
    e[++len].to=y;
    e[len].from=x;
    e[len].dis=dis;
    e[len].next=head[x];
    head[x]=len;
}
int n,m,k;
bool cmp(int x,int y){
    return x>y;
}
void prim(int st){
    for(int i=1;i<=n;++i)diss[i]=0x3f3f3f3f;
    priority_queue<node>q;
    q.push((node){st,0});
    diss[st]=0;
    while(!q.empty()){
        node x=q.top();
        int id=x.id;
        q.pop();
        if(!vis[id]){
           vis[id]=1;
           MST[st]+=diss[id];
           d[++Len]=diss[id];
           for(int i=head[id];i;i=e[i].next){
               int v=e[i].to;
               diss[v]=min(diss[v],e[i].dis);
               if(!vis[v]){
                   q.push((node){v,diss[v]});
               }
           }
        }
    }
}
void work(){
    scanf("%d%d%d",&n,&m,&k);
    for(int i=1;i<=m;++i){
        int x,y,z;
        scanf("%d%d%d",&x,&y,&z);
        Insert(x,y,z);Insert(y,x,z);
    }
    for(int i=1;i<=n;++i){
        if(!vis[i]){
           if(!k){
               printf("-1\n");return;
           }
           prim(i);k--;
        }       
    }
    for(int i=1;i<=n;++i){
        if(MST[i]){
            ans+=MST[i];
        }
    }
    sort(d+1,d+Len+1,cmp);
    int i=1;
    while(k){
        ans-=d[i];k--;i++;
    }
    printf("%lld\n",ans);
}
int main(){
    freopen("room.in","r",stdin);
    freopen("room.out","w",stdout);
    work();
    return 0;
}

Kruskal

基于边构造最小生成树,一开始可以看做有n个连通块,目标是构造最小生成树使得图变成k个连通块。连边实际上就是把两个连通块连到一起,连通块==k时跳出循环,此时求出MST大小即为答案

Code


void kruskal()
{
	int tot = n;//连通块
    long long ans = 0;
	for (int i = 1; i <= m; ++i) {
		int u = from[i], v = to[i];
		u = Find(u), v = Find(v);
		if (u == v) continue;
		--tot;
		ans += dis[i];
		f[v] = u;
        if (tot == k) {
            printf("%lld\n", ans);
            return;
        }
	}
    printf("-1\n");
}

posted @   Chano_sb  阅读(196)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 【.NET】调用本地 Deepseek 模型
· CSnakes vs Python.NET:高效嵌入与灵活互通的跨语言方案对比
· DeepSeek “源神”启动!「GitHub 热点速览」
· 我与微信审核的“相爱相杀”看个人小程序副业
· Plotly.NET 一个为 .NET 打造的强大开源交互式图表库
点击右上角即可分享
微信分享提示