並查集/DFS-CodeForces 1027D-Mouse Hunt

  • 並查集/DFS-CodeForces 1027D-Mouse Hunt


  • 題目鏈接:

D. Mouse Hunt

  • 題目基礎:並查集

數據結構-並查集

  • 思路:

題目大意:

給定兩個N長度序列,第一個序列表示在每個房間安裝捕鼠器的成本,第二個序列是狀態圖,表示在第 i 個房間的老鼠,下一秒會去到房間 Next_Room[i] (可以選擇停留在該房間),求出一定能捉到老鼠的最小成本

題解:

怎樣放捕鼠器才能讓老鼠一定被捉到?其實就是放在老鼠在房間中活動形成的環路,想要最小成本,在每個環中選出安裝捕鼠器成本最低的房間

那要怎麼檢查老鼠活動是否成環?用到並查集,如果檢查的兩個元素在一個集合中,說明成環(兩種成環狀態,自環-當老鼠停留在原來房間,或者多房間成環)

然後用深搜找出每個環安裝捕鼠器的最小成本

  • 代碼:

#include<bits/stdc++.h>
using namespace std;
#define MAX_SIZE 200005
int Node[MAX_SIZE];
int Height[MAX_SIZE];
int Burles[MAX_SIZE];
int Next_Room[MAX_SIZE];
int Judge[MAX_SIZE];
void Init(int n)   //初始化結點
{
    for(int i=0;i<=n;i++)
    {
        Node[i]=-1;
        Height[i]=0;
        Judge[i]=0;
    }
}

int Find(int x)   //查找集合根
{
    if(Node[x]==-1)
        return x;
    else
        return Node[x]=Find(Node[x]); //查找到x的根時,將x直接連到根
}

int Combine(int a,int b)   //a b 符合某種關係需合併,如果a b本同屬一個集合,返回0
{
    int a_root=Find(a);
    int b_root=Find(b);
    if(a_root==b_root)
        return 0;
    if(Height[a_root]<Height[b_root])   //小樹a放在b下
        Node[a_root]=b_root;
    else
    {
        Node[b_root]=a_root;
        if(Height[a_root]==Height[b_root])
            Height[a_root]++;
    }
    return 1;
}
int DFS(int x,int y)
{
    if(x==y)
        return Burles[x];

    return min(DFS(Next_Room[x],y),Burles[x]);
}

int main()
{
    int n;
    int Res=0;
    cin>>n;
    Init(n);
    for(int i=1;i<=n;i++)
        scanf("%d",&Burles[i]);
    for(int i=1;i<=n;i++)
    {
        scanf("%d",&Next_Room[i]);
        if(!Combine(i,Next_Room[i]))   //兩個房間已在集合內,說明有成環情況,標記
            Judge[i]=1;
    }
    for(int i=1;i<=n;i++)
    {
        if(Judge[i])
            Res+=DFS(Next_Room[i],i);
    }
    cout<<Res<<endl;
    return 0;
}

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章