1. 程式人生 > 其它 >P2403 [SDOI2010]所駝門王的寶藏

P2403 [SDOI2010]所駝門王的寶藏

[SDOI2010]所駝門王的寶藏

題目描述

在寬廣的非洲荒漠中,生活著一群勤勞勇敢的羊駝家族。被族人恭稱為“先知”的Alpaca L. Sotomon是這個家族的領袖,外人也稱其為“所駝門王”。所駝門王畢生致力於維護家族的安定與和諧,他曾親自率軍粉碎河蟹帝國主義的野蠻侵略,為族人立下赫赫戰功。所駝門王一生財寶無數,但因其生性節儉低調,他將財寶埋藏在自己設計的地下宮殿裡,這也是今天Henry Curtis故事的起點。Henry是一個愛財如命的貪婪傢伙,而又非常聰明,他費盡心機謀劃了這次盜竊行動,破解重重機關後來到這座地下宮殿前。 整座宮殿呈矩陣狀,由R×C間矩形宮室組成,其中有N間宮室裡埋藏著寶藏,稱作藏寶宮室。宮殿裡外、相鄰宮室間都由堅硬的實體牆阻隔,由一間宮室到達另一間只能通過所駝門王獨創的移動方式——傳送門。所駝門王為這N間藏寶宮室每間都架設了一扇傳送門,沒有寶藏的宮室不設傳送門,所有的宮室傳送門分為三種:
1. “橫天門”:由該門可以傳送到同行的任一宮室; 2. “縱寰門”:由該門可以傳送到同列的任一宮室; 3. “任意門”:由該門可以傳送到以該門所在宮室為中心周圍8格中任一宮室(如果目標宮室存在的話)。 深謀遠慮的Henry當然事先就搞到了所駝門王當年的宮殿招標冊,書冊上詳細記錄了每扇傳送門所屬宮室及型別。而且,雖然宮殿內外相隔,但他自行準備了一種行動式傳送門,可將自己傳送到殿內任意一間宮室開始尋寶,並在任意一間宮室結束後傳送出宮。整座宮殿只許進出一次,且便攜門無法進行宮室之間的傳送。不過好在宮室內傳送門的使用沒有次數限制,每間宮室也可以多次出入。 現在Henry已經打開了便攜門,即將選擇一間宮室進入。為得到盡多寶藏,他希望安排一條路線,使走過的不同藏寶宮室儘可能多。請你告訴Henry這條路線最多行經不同藏寶宮室的數目。

輸入輸出格式

輸入格式

輸入檔案sotomon.in第一行給出三個正整數N, R, C。 以下N行,每行給出一扇傳送門的資訊,包含三個正整數xi, yi, Ti,表示該傳送門設在位於第xi行第yi列的藏寶宮室,型別為Ti。Ti是一個1~3間的整數,1表示可以傳送到第xi行任意一列的“橫天門”,2表示可以傳送到任意一行第yi列的“縱寰門”,3表示可以傳送到周圍8格宮室的“任意門”。 保證1≤xi≤R,1≤yi≤C,所有的傳送門位置互不相同。

輸出格式

輸出檔案sotomon.out只有一個正整數,表示你確定的路線所經過不同藏寶宮室的最大數目。

輸入輸出樣例

輸入樣例 #1

10 7 7
2 2 1
2 4 2
1 7 2
2 7 3
4 2 2
4 4 1
6 7 3
7 7 1
7 5 2
5 2 1

輸出樣例 #1

9

說明

資料規模和約定:

分析:各個房間之間的路經滿足有向關係,可以重複經過每一個房間多次,求最多經過的房間數目。可以想到縮點,在整張圖跑 tarjan 演算法縮點,重新連邊然後在DAG上跑拓撲排序或者記憶化搜尋。

但是如果我們暴力建邊的話時間複雜度和空間複雜度都是$O(n ^ {2} )$的,難以接受

所以本題的問題就是如何優化建邊

考慮到等效性原則,對於每一個向本列(本行)連邊的點,都有一條有向邊指向每一個本列(本行)的其他點。

可以新建一個虛擬原點$U$[U初始化會連線該行/列的每一個點],通過讓這個點向$U$連邊,達到等效的效果

1 ~ r :每一行的超級原點

r + 1 ~ r + c :每一列的超級原點

r + c + 1 ~ r + c + n :原始點

對於第三種點,我們可以預先用map存下每一個座標對應點的序號,對這種點加邊時直接列舉周圍8個點,查詢對應點的序號就行了

細節 :

  1. r 和 c 直接取成 $max(a_i.x) 和 max(a_i.y)$ 多餘的捨去

  2. 統計強連通分量的大小時去掉虛擬點(u <= r + c)

  3. map 記錄兩個強連通分量之間是否已經加過邊,判重

#include <cstdio>
#include <cstring>
#include <algorithm>
#include <vector>
#include <map>

using namespace std;

const int N = 2e6 + 10 + 1e5, NN = 1e5 + 10;


vector  v[N], vv[NN * 4];

int vis[NN];


int n, r, c;

struct node
{
    int val;
    int x, y;
}a[NN];

int dfn[N], low[N], timestamp;

int scc_cnt, size[N], id[N];

int stk[N], in_stk[N], top;

map <int ,int>  Ma;
map <int , bool> M;
void tarjan(int u)
{
    // for(int i = 1; i <= top; i++) printf("%d ", stk[i]);
    // printf("\n");

    if(!v[u].size() && u <= r + c) return ;

    dfn[u] = low[u] = ++timestamp;
    in_stk[u] = 1; stk[++top] = u;
    for(int i = 0 ; i < v[u].size(); ++i)
    {
        int j = v[u][i];

        if(!dfn[j])
        {
            tarjan(j);
            low[u] = min(low[u], low[j]);
        }
        else if(in_stk[j])
        {
            low[u] = min(low[u], dfn[j]);
        }
    }
    if(low[u] == dfn[u])
    {
        ++scc_cnt;
        int y;
        do
        {
            y = stk[top--];
            id[y] = scc_cnt;
            size[scc_cnt] += (y > r + c);
          //  if(y > r + c) col[scc_cnt].push_back(y);
            in_stk[y] = 0;  
        } while (y != u);
    }

}

int f[N];

int dp(int u)
{
    if(f[u] > 0) return f[u];
    int res = 0;
    for(int i = 0 ; i < vv[u].size(); i++)
    {
        int j = vv[u][i];
        res = max(res, dp(j));
    }
    return f[u] = res + size[u];

}

int dx[8] = {1, 1, 1, 0, 0, -1, -1, -1};
int dy[8] = {1, 0, -1, 1,-1, 1, 0, -1};

int main()
{
    //freopen("1.in", "r", stdin);
    scanf("%d %d %d", &n, &r, &c);
    M.clear(); Ma.clear();

    int rr = -1, cc = -1;

    for(int i = 1; i <= n; i++)
    {
        scanf("%d %d %d", &a[i].x, &a[i].y, &a[i].val);
        Ma[{a[i].x, a[i].y}] = i;
        rr = max(a[i].x, rr);
        cc = max(a[i].y, cc);
    }
    r = min(rr , r);
    c = min(cc, c);

    for(int i = 1; i <= n; i++)
    {
        v[a[i].x].push_back(i + c + r);
        v[r + a[i].y].push_back(i + r + c);
        if(a[i].val == 1) v[i + r + c].push_back(a[i].x);
        else if(a[i].val == 2)
        {
            v[r + c + i].push_back(r + a[i].y);
        }
        else
        {
            int x = a[i].x , y = a[i].y;
            for(int j = 0; j < 8; j++)
            {
                int xx = x + dx[j];
                int yy = y + dy[j];
                if(Ma[{xx, yy}])
                {
                    v[r + c + i].push_back(Ma[{xx, yy}] + r + c);
                }
            }
        }
    }

    for(int i = 1; i <= n + r + c; i++)
    {
        if(!dfn[i])
        {
            if(!v[i].size() && i <= r + c) continue;
            tarjan(i);
        }
    }
    for(int i = 1; i <= n + r + c; i++)
    {
        for(int j = 0; j < v[i].size(); j++)
        {
            int a = id[i], b = id[v[i][j]];
            if(a == b || M[{a, b}] ) continue;
            M[{a, b}] = 1;
            vv[a].push_back(b);
        }
    }

    int res = 0;
    for(int i = 1; i <= scc_cnt; i++) 
    {
        res = max(res, dp(i));
    }
    
    
    printf("%d", res);
    return 0;

}