E.Avoid Rainbow Cycles (生成树模型)

E.Avoid Rainbow Cycles
题意:
有m个集合,n个点,每个集合有一些1到n的数,这些数代表的点构成一个完全图,边的颜色为i(第i个集合),然后定义彩虹环是一个环,这个环上的所有边都是不同颜色的,每次操作可以删除一个集合中的一个点,花费为a[i]+b[j],代表第i个集合的第j点,求最小花费使得最终不存在彩虹环。
思路:
这个题很难下手,因为彩虹环定义和完全图这些东西太绕了,但是其实可以定义一个点n+i,连着第i集合中的所有点,这样其实也就成了完全图,就抽象为了某个点,经过第n+i个点(即i颜色的边)到达另一个点,这个和克鲁斯重构树差不多,把边化为点,然后这样的话最终一定得是个树才行,否则只要有环,则一定是存在彩虹环,因为点和点之间没有任何连边,所以这个图一定是点-边-点-边这种的形式,所以出现了环,则某个点一定是连接了至少两个不同颜色边,因此肯定出现了彩虹环,因此题目就可以转化为求最小花费使得这个图变成一棵树,这样就可以变成了最大生成树问题。
总结:如果碰到了这种的完全图问题,可以建立一个总点,这样就可以简化图了,从而使得模型更加清晰简约,这个题稍微有些重构树的思想,这种模型确实很神奇。

#include<iostream>
#include<cstdio>
#include<algorithm>
using namespace std;
const int MAX_N=101000;
long long a[MAX_N],b[MAX_N];
struct skt{
    int x,y;
    long long z;
}edge[2*MAX_N];
int pre[2*MAX_N];
bool cmp(skt a,skt b){
    return a.z>b.z;
}
int find(int x){
    if(pre[x]!=x)
    pre[x]=find(pre[x]);
    return pre[x];
}
int main(void){
    int n,m,i,j,k;
    scanf("%d%d",&m,&n);
    for(i=1;i<=m;i++)
    scanf("%lld",&a[i]);
    for(i=1;i<=n;i++)
    scanf("%lld",&b[i]);
    for(i=1;i<=n+m;i++)
    pre[i]=i;
    int cnt=0;
    long long res=0;
    for(i=1;i<=m;i++){
        int x;
        scanf("%d",&k);
        for(j=1;j<=k;j++){
            scanf("%d",&x);
            edge[++cnt].x=n+i,edge[cnt].y=x,edge[cnt].z=a[i]+b[x];
            res+=edge[cnt].z;
        }
    }
    sort(edge+1,edge+cnt+1,cmp);
    for(i=1;i<=cnt;i++){
        int x=edge[i].x,y=edge[i].y;
        long long z=edge[i].z;
        int fx=find(x),fy=find(y);
        if(fx!=fy){
            pre[fx]=fy;
            res-=z;
        }
    }
    printf("%lld\n",res);
    return 0;
} 
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值