CF Grakn Forces 2020 1408E Avoid Rainbow Cycles(最小生成樹)

1408E Avoid Rainbow Cycles

概述

很是有趣的題目(指解法,不難,但很難想)c++

很是崇拜300iq,今天想作一套div1時看見了他出的這套題Grakn Forces 2020,就立馬開始補這套題,果真不出我所料,全是iq題(誤spa

題目

m個set中有1-n的一些數,首先咱們能夠把一個數 j 從set i 中刪除,代價是 \(a[i]+b[j]\) ,至於爲何要刪除以後再說code

接着咱們對於每一個set i\(\forall x,y \in i\),建邊\((x,y)\)並染色爲 \(i\)get

最後咱們定義\(Rainbow Cycle\)爲從某個節點x 出發,通過一個迴路可以從新回到x 且,迴路中的邊顏色兩兩各不相同it

問題是求出最小的刪除費用使得圖中沒有\(RainbowCycle\)class

題解

核心:建圖跑最小生成樹test

建圖方式:數 \(j\) 在set \(i\) 裏就建一條邊\((n+i,j)\) ,這樣實際上每一個\(x,y\)在set裏的都已經聯通了,\(RainbowCycle\) 其實就變成了新圖裏的一條普通迴路總結

問題就很明顯了,一個沒有環的圖且刪邊費用最小就是最大生成樹sort

總結

\((x,y)\)邊染色爲\(z\),能夠增長一個新節點\(n+z(防止點重複)\) ,建兩條邊\((x,n+z),(n+z,y)\) 這樣方便對邊進行操做di

代碼

#include<bits/stdc++.h>
using namespace std;
#define ll long long
const int N=2e5+10;
int pre[N],tot=0;
ll a[N],b[N];
struct E
{
    int x,y;
    ll val;
    E(int x1,int y1,ll val1){
        x=x1;y=y1;val=val1;
    };
    E(){
        x=y=val=0;  
    };
}edge[2*N];
bool cmp(E x,E y)
{
    return x.val>y.val;
}
int find(int x)
{
    if(pre[x]==x) return x;
    else return pre[x]=find(pre[x]);
}
int merge(int x,int y)
{
    int fx=find(x),fy=find(y);
    if(fx==fy) return 0;
    pre[fx]=fy;
    return 1;
}
int main()
{
    int n,m;
    scanf("%d%d",&m,&n);
    for(int i=1;i<=m;i++) scanf("%lld",&a[i]);
    for(int j=1;j<=n;j++) scanf("%lld",&b[m+j]);
    for(int i=1;i<=m+n;i++) pre[i]=i;
    for(int i=1;i<=m;i++){
        int x;scanf("%d",&x);
        for(int j=1;j<=x;j++){
            int y;scanf("%d",&y);
            E cnt(i,m+y,a[i]+b[m+y]);
            edge[++tot]=cnt;
        }
    }
    sort(edge+1,edge+tot+1,cmp);
    ll res=0;
    for(int i=1;i<=tot;i++){
        E cnt=edge[i];
        int x=cnt.x,y=cnt.y;
        if(merge(x,y)){
            continue;
        }
        else{
            res+=cnt.val;
            //cout<<x<<' '<<y<<' '<<cnt.val<<endl;
        }
    }
    printf("%lld\n",res);
}
相關文章
相關標籤/搜索