天梯賽 並查集相關題目

L2-007 家庭房產 (25 分)

 

 

給定每個人的家庭成員和其自己名下的房產,請你統計出每個家庭的人口數、人均房產面積及房產套數。

輸入格式:

輸入第一行給出一個正整數N(≤1000),隨後N行,每行按下列格式給出一個人的房產:


 

其中編號是每個人獨有的一個4位數的編號;分別是該編號對應的這個人的父母的編號(如果已經過世,則顯示-1);k(0≤k≤5)是該人的子女的個數;孩子i是其子女的編號。

輸出格式:

首先在第一行輸出家庭個數(所有有親屬關係的人都屬於同一個家庭)。隨後按下列格式輸出每個家庭的信息:


 

其中人均值要求保留小數點後3位。家庭信息首先按人均面積降序輸出,若有並列,則按成員編號的升序輸出。

 

噁心。。。

用並查集合並當前這個人和他的父母以及兒子,合併爲最小的下標

然後再開一個數組去搞會方便一點

#include <iostream>
#include <queue>
#include <map>
#include <cmath>
#include <set>
#include <iomanip>
#include <iomanip>
#include <unordered_set>
#include <cstring>
#include <unordered_map>
#include <algorithm>
using namespace std;
const int maxn=10005;
int n;
int pre[maxn];

struct node
{
    int id;
    int fa=0,ma=0;
    int num=0;
    double area=0;
    int peo=0;
    double areas=0;
}a[maxn],ans[maxn];

int uni(int root)
{
    int son,tem;
    son=root;
    while(root!=pre[root])
    {
        root=pre[root];
    }
    while(son!=root)
    {
        tem=pre[son];
        pre[son]=root;
        son=tem;
    }
    return root;
}

void join(int x,int y)
{
    x=uni(x);
    y=uni(y);
    if(x>y)
    {
        pre[x]=y;
    }
    else  pre[y]=x;
}

bool cmp(node a,node b)
{
    if(a.areas==b.areas)
    {
        return a.id<b.id;
    }
    return a.areas>b.areas;
}

int main()
{
    ios::sync_with_stdio(false);
    cin>>n;
    int k;
    int summ=0;
    for(int i=0;i<10000;i++)pre[i]=i;
    for(int i=1;i<=n;i++)
    {
        cin>>a[i].id>>a[i].fa>>a[i].ma>>k;
        if(a[i].fa!=-1)
        {
            join(a[i].fa,a[i].id);
        }
        if(a[i].ma!=-1)
        {
            join(a[i].ma,a[i].id);
        }
        int son;
        for(int j=1;j<=k;j++)
        {
            cin>>son;
            join(a[i].id,son);
        }
        cin>>a[i].num>>a[i].area;
    }
    int x;
    for(int i=1;i<=n;i++)
    {
        x=uni(a[i].id);//找根節點
        ans[x].id=x;
        ans[x].area+=a[i].area;
        ans[x].num+=a[i].num;
        ans[x].fa=-1;
    }
    //cout<<"summ"<<summ<<endl;
    for(int i=0;i<10000;i++)
    {
        ans[uni(i)].peo++;
        if(ans[i].fa==-1){
            summ++;
        }
    }
    for(int i=0;i<10000;i++)
    {
        if(ans[i].fa==-1)
        {
            ans[i].areas=ans[i].area/ans[i].peo;
        }
    }
    cout<<summ<<endl;
    sort(ans,ans+9999,cmp);
    for(int i=0;i<summ;i++)
    {
        cout<<setfill('0')<<setw(4)<<ans[i].id;
        cout<<' '<<ans[i].peo<<' ';
        cout<<fixed<<setprecision(3)<<(double)ans[i].num/ans[i].peo<<' '
        <<ans[i].areas<<endl;
    }



    return 0;
}

 

L2-010 排座位 (25 分)

佈置宴席最微妙的事情,就是給前來參宴的各位賓客安排座位。無論如何,總不能把兩個死對頭排到同一張宴會桌旁!這個艱鉅任務現在就交給你,對任何一對客人,請編寫程序告訴主人他們是否能被安排同席。

輸入格式:

輸入第一行給出3個正整數:N(≤100),即前來參宴的賓客總人數,則這些人從1到N編號;M爲已知兩兩賓客之間的關係數;K爲查詢的條數。隨後M行,每行給出一對賓客之間的關係,格式爲:賓客1 賓客2 關係,其中關係爲1表示是朋友,-1表示是死對頭。注意兩個人不可能既是朋友又是敵人。最後K行,每行給出一對需要查詢的賓客編號。

這裏假設朋友的朋友也是朋友。但敵人的敵人並不一定就是朋友,朋友的敵人也不一定是敵人。只有單純直接的敵對關係纔是絕對不能同席的。

輸出格式:

對每個查詢輸出一行結果:如果兩位賓客之間是朋友,且沒有敵對關係,則輸出No problem;如果他們之間並不是朋友,但也不敵對,則輸出OK;如果他們之間有敵對,然而也有共同的朋友,則輸出OK but...;如果他們之間只有敵對關係,則輸出No way

 

 

並查集朋友,因爲朋友的朋友也是朋友,對於敵人直接標記

 

#include <bits/stdc++.h>
using namespace std;
const int maxn=1e3+5;
int pre[maxn];
set<int>s[maxn];
int uni(int root)
{
    int son, tem;

        son = root;
        while (root != pre[root])
        {
            root = pre[root];
        }
        while (son != root)
        {
            tem = pre[son];
            pre[son] = root;
            son = tem;
        }
        return root;
}

int main()
{
    ios::sync_with_stdio(false);
    int n,m,k;
    int x,y,tem;
    cin>>n>>m>>k;
    for(int i=1;i<=n;i++)
    {
        pre[i]=i;
    }
    for(int i=1;i<=m;i++)
    {
        int xx,yy;
        cin>>x>>y>>tem;
        if(tem==1)
        {
            xx=uni(x);
            yy=uni(y);
            pre[xx]=yy;
        }
        else
        {
            s[y].insert(x);
            s[x].insert(y);
        }
    }
    for(int i=1;i<=k;i++)
    {
        cin>>x>>y;
        if(!s[x].empty()&&s[x].find(y)!=s[x].end())
        {
            if(uni(x)!=uni(y))
            {
                cout<<"No way"<<endl;
            }
            else cout<<"OK but..."<<endl;
        }
        else
        {
            if(uni(x)==uni(y))
            {
                cout<<"No problem"<<endl;
            }
            else cout<<"OK"<<endl;
        }
    }


    return 0;
}

 

L2-013 紅色警戒

並查集一下記錄個數,如果刪除前的個數=刪除後的個數或者刪除前的個數=刪除後的個數-1,那麼刪除這個點就沒有影響

其他情況是有影響的

 

#include <bits/stdc++.h>
#define quickio ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
using namespace std;
#define ll long long
int n,m;
const  int maxn=5005;
int pre[maxn];

int uni(int x)
{
    return x==pre[x]?pre[x]:uni(pre[x]);
}
void join(int x,int y)
{
    int xx=uni(x);
    int yy=uni(y);
    pre[xx]=yy;
}

int main()
{
    int u[maxn],v[maxn];
    cin>>n>>m;
    for(int i=0;i<n;i++)pre[i]=i;

    for(int i=1;i<=m;i++)
    {
        cin>>u[i]>>v[i];
        join(u[i],v[i]);
    }

    int k;
    int a;
    int num=0;
    int new_num=0;

    cin>>k;
    for(int i=0;i<n;i++)
    {
        if(pre[i]==i)
        {
            num++;
        }
    }
    set<int>s;

    for(int i=1;i<=k;i++)
    {
        new_num=0;
        cin>>a;
        s.insert(a);
        for(int j=0;j<n;j++)pre[j]=j;

        for(int j=1;j<=m;j++)
        {
            if(s.find(u[j])!=s.end()||s.find(v[j])!=s.end())
                continue;
            join(u[j],v[j]);
        }
        for(int j=0;j<n;j++)
        {
            if(s.find(j)!=s.end())continue;
            if(pre[j]==j)
            {
                new_num++;
            }
        }

        if(new_num==num||new_num==num-1)
        {
            cout<<"City "<<a<<" is lost."<<endl;
        }
        else cout<<"Red Alert: City "<<a<<" is lost!"<<endl;
        if((int)s.size()==n)
        {
            cout<<"Game Over."<<endl;
        }
        num=new_num;
    }


    return 0;
}

 

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