Educational Codeforces Round 31 C.Bertown Subway(圖論)

題目鏈接:Bertown Subway
題意:簡單地說,就是給一個n個地鐵站的線路圖,每個地鐵站i有一趟地鐵從i站出發,到達目的站pi,pi可以等於i 且 滿足條件: 對於每個i站,只存在一個j站使得pj=i。定義有序對pair(a,b)表示從a站到b站,現在給你一個機會在滿足條件下可以改變不超過兩個地鐵站的pi,使得(a,b)的個數最多,問最多個數是多少?
題解:題目先輸入一個n,在輸入pi,而且每個pi是不同的,再加上題目要求的條件,這道題只會存在多個環(多個強聯通分量),而且每個環之間必然沒有有向邊。可能一個點成環,也可能多個點成環,那麼依據路徑把同環的點分組,並統計該組有多少個點,點數從大到小排個序。根據有向圖的強聯通分量,合併兩個強聯通分量在每個強聯通分量改一條邊指向另一個強聯通分量即可合成一個強聯通分量。要想pair(a,b)的個數最多,自然就是把點數最多的兩個強聯通分量合併嘛,因爲按照定義,每個強聯通分量的pair(a,b)個數計算都是該強聯通分量的點數點數。所以把大的兩個合併後,遍歷每個強聯通分量,累加所有強聯通分量的點數點數即可。這道題我想到強聯通分量,開始還想用Tarjan做,但發現根本不用,根據路徑用dfs把點分下組就好了。
時間複雜度O(n)

#include <iostream>
#include <cstdio>
#include <fstream>
#include <algorithm>
#include <cmath>
#include <deque>
#include <vector>
#include <queue>
#include <string>
#include <cstring>
#include <map>
#include <stack>
#include <set>
#define Max(a,b) a>b?a:b
#define Min(a,b) a>b?b:a
#define mem(a,b) memset(a,b,sizeof(a))
using namespace std;
typedef long long ll;
int dir[4][2]= {{1,0},{-1,0},{0,1},{0,-1}};
const double eps = 1e-6;
const double Pi = acos(-1.0);
const int INF=0x3f3f3f3f;
const int maxn = 1e5+10;
int n,cnt;
int p[maxn];
struct PointSet{
    int start;
    int step;
    PointSet(int sta = 0, int ste = 0) : start(sta), step(ste) {}
};
PointSet sett[maxn];
bool vis[maxn];

void dfs(int i){
    while(!vis[i]){
        vis[i] = true;
        sett[cnt].step++;
        i = p[i];
    }
}

bool cmp(const PointSet &a, const PointSet &b){
    return a.step > b.step;
}

int main(){
    ll ans = 0;
    scanf("%d",&n);
    for(int i = 1 ; i <= n; i++){
        scanf("%d",&p[i]);
    }
    memset(vis,false,sizeof(vis));
    cnt = 0;

    for(int i = 1; i <= n; i++){
        if(!vis[i]){
            sett[cnt] = PointSet(i,0);
            dfs(i);
            cnt++;
        }
    }

    sort(sett,sett+cnt,cmp);
    if(cnt < 2){
        printf("%lld",(ll)sett[0].step*sett[0].step);
    }else{
        ans += (ll)(sett[0].step+sett[1].step)*(sett[0].step+sett[1].step);
        for(int i = 2; i < cnt; i++){
            ans += (ll)sett[i].step*sett[i].step;
        }
        printf("%lld",ans);
    }



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