1. 程式人生 > >BZOJ 1924: [Sdoi2010]所駝門王的寶藏 題解

BZOJ 1924: [Sdoi2010]所駝門王的寶藏 題解

amp print sam main scrip ac代碼 盡心 ons getc

此文為博主原創題解,轉載時請通知博主,並把原文鏈接放在正文醒目位置。

題目鏈接:http://www.lydsy.com/JudgeOnline/problem.php?id=1924

Description

在寬廣的非洲荒漠中,生活著一群勤勞勇敢的羊駝家族。被族人恭稱為“先知”的 Alpaca L. Sotomon 是這個家族的領袖,外人也稱其為“所駝門王”。

所駝門王畢生致力於維護家族的安定與和諧,他曾親自率軍粉碎河蟹帝國主義的野蠻侵略,為族人立下赫赫戰功。

所駝門王一生財寶無數,但因其生性節儉低調, 他將財寶埋藏在自己設計的地下宮殿裏,這也是今天 Henry Curtis 故事的起點。

Henry 是一個愛財如命的貪婪家夥,而又非常聰明,他費盡心機謀劃了這次盜竊行動,破解重重機關後來到這座地下宮殿前。

整座宮殿呈矩陣狀,由 R×C 間矩形宮室組成,其中有 N 間宮室裏埋藏著寶藏,稱作藏寶宮室。

宮殿裏外、相鄰宮室間都由堅硬的實體墻阻隔,由一間宮室到達另一間只能通過所駝門王獨創的移動方式——傳送門。

所駝門王為這 N 間藏寶宮室每間都架設了一扇傳送門,沒有寶藏的宮室不設傳送門,所有的宮室傳送門分為三種:

1、“橫天門”:由該門可以傳送到同行的任一宮室;

2、“縱寰門”:由該門可以傳送到同列的任一宮室;

3、“free門”:由該門可以傳送到以該門所在宮室為中心周圍8格中任一宮室(如果目標宮室存在的話)。

深謀遠慮的 Henry 當然事先就搞到了所駝門王當年的宮殿招標冊,書冊上詳細記錄了每扇傳送門所屬宮室及類型。

而且,雖然宮殿內外相隔,但他自行準備了一種便攜式傳送門,可將自己傳送到殿內任意一間宮室開始尋寶,並在任意一間宮室結束後傳送出宮。

整座宮殿只許進出一次,且便攜門無法進行宮室之間的傳送。不過好在宮室內傳送門的使用沒有次數限制,每間宮室也可以多次出入。

現在 Henry 已經打開了便攜門,即將選擇一間宮室進入。

為得到盡多寶藏, 他希望安排一條路線,使走過的不同藏寶宮室盡可能多。請你告訴 Henry 這條路線最多行經不同藏寶宮室的數目。

Input

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

Output

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

Sample Input

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

Sample Output

9 分析: 【zi由門居然是違禁內容...也是服氣...】 在藏寶宮室之間建邊,同類別門建立雙向邊,不同類別門建立雙向邊。free門用map進行處理。 邊全部連好之後跑一遍tarjan縮點,然後再建一個新的DAG,DP求最短路。 難點主要就是建邊的時候比較麻煩...vector,map什麽的都上了...思路還是比較好想的。 (代碼)參考博客:hzwer 嘒彼小星 AC代碼
  1 #include<cstdio>
  2 #include<algorithm>
  3 #include<cmath>
  4 #include<cstring>
  5 #include<vector>
  6 #include<stack>
  7 #include<map>
  8 
  9 const int MAXN = 1000002;
 10 inline void read(int &x)
 11 {
 12     char ch = getchar(),c = ch;x = 0;
 13     while(ch < 0 || ch > 9) c = ch,ch = getchar();
 14     while(ch <= 9 && ch >= 0) x = (x<<1)+(x<<3)+ch-0,ch = getchar();
 15     if(c == -) x = -x;
 16 }
 17 
 18 std::vector<int> a[MAXN],b[MAXN];
 19 std::map <int,int> mp[MAXN];
 20 std::stack <int> s;
 21 int k,m,n,cnt,ans,dfn_cnt,part;
 22 int x[MAXN],y[MAXN],op[MAXN],head[MAXN],first[MAXN];
 23 int dfn[MAXN],low[MAXN],belong[MAXN],sum[MAXN],calc[MAXN];
 24 
 25 inline int Max(int a,int b)
 26 {return a>b?a:b;}
 27 
 28 inline int Min(int a,int b)
 29 {return a<b?a:b;}
 30 
 31 struct Edge
 32 {
 33     int f,t,nxt;
 34 }e[MAXN],New[MAXN];
 35 
 36 void insert(int f,int t)
 37 {
 38     e[++cnt].f = f,e[cnt].t = t;
 39     e[cnt].nxt = head[f];
 40     head[f] = cnt;
 41 }
 42 
 43 void New_insert(int f,int t)
 44 {
 45     New[++cnt].f = f,New[cnt].t = t;
 46     New[cnt].nxt = first[f];
 47     first[f] = cnt;
 48 }
 49 
 50 void build()
 51 {
 52     //建立橫天門 
 53     for(int i = 1;i <= n;++ i)
 54     {
 55         int tmp = 0,t = a[i].size();
 56         for(int j = 0;j < t;++ j)
 57             if(op[a[i][j]] == 1){
 58                 tmp = a[i][j];break;
 59             }
 60         for(int j = 0;j < t;++ j)
 61         {
 62             insert(tmp,a[i][j]);
 63             if(op[a[i][j]] == 1)
 64                 insert(a[i][j],tmp);
 65         }
 66     }
 67     //建立縱寰門 
 68     for(int i = 1;i <= m;++ i)
 69     {
 70         int tmp = 0,t = b[i].size();
 71         for(int j = 0;j < t;++ j)
 72             if(op[b[i][j]] == 2){
 73                 tmp = b[i][j];break;
 74             }
 75         for(int j = 0;j < t;++ j)
 76         {
 77             insert(tmp,b[i][j]);
 78             if(op[b[i][j]] == 2)
 79                 insert(b[i][j],tmp);
 80         }
 81     }
 82     //建立free門 
 83     for(int i = 1;i <= k;++ i)
 84         if(op[i] == 3)
 85             for(int h = -1;h <= 1;++ h)
 86                 for(int z = -1;z <= 1;++ z)
 87                 {
 88                     if(!h && !z) continue;
 89                     int t = mp[x[i]+h][y[i]+z];
 90                     if(t) insert(i,t);
 91                 }
 92 }
 93 
 94 void Tarjan(int u)
 95 {
 96     dfn[u] = low[u] = ++ dfn_cnt;
 97     s.push(u);
 98     for(int i = head[u];i;i = e[i].nxt)
 99     {
100         int v = e[i].t;
101         if(!dfn[v])
102         {
103             Tarjan(v);
104             low[u] = Min(low[u],low[v]);
105         }
106         else if(!belong[v])
107             low[u] = Min(low[u],dfn[v]);
108     }
109     if(dfn[u] == low[u])
110     {
111         part ++;
112         while(!s.empty())
113         {
114             int tmp = s.top();
115             s.pop();
116             belong[tmp] = part;
117             sum[part] ++;
118             if(tmp == u) break;
119         }
120     }
121 }
122 
123 void rebuild()
124 {
125     cnt = 0;
126     for(int i = 1;i <= k;++ i)
127         for(int j = head[i];j;j = e[j].nxt)
128         {
129             int t = e[j].t;
130             if(belong[i] != belong[t])
131                 New_insert(belong[i],belong[t]);
132         }
133 }
134 
135 int dp(int u)
136 {
137     if(calc[u]) return calc[u];
138     calc[u] = sum[u];
139     for(int i = first[u];i;i = New[i].nxt)
140         calc[u] = Max(calc[u],dp(New[i].t)+sum[u]);
141 
142     ans = Max(ans,calc[u]);
143     return calc[u];
144 }
145 
146 int main()
147 {
148     read(k),read(n),read(m);
149     for(int i = 1;i <= k;++ i)
150     {
151         read(x[i]),read(y[i]),read(op[i]);
152         mp[x[i]][y[i]] = i;
153         a[x[i]].push_back(i);
154         b[y[i]].push_back(i);
155     }
156     build();//建立原圖 
157     //縮點變為DAG 
158     for(int i = 1;i <= k;++ i)
159         if(!dfn[i])
160             Tarjan(i);
161     rebuild();//重建圖 
162     for(int i = 1;i <= part;++ i)
163         dp(i);//DAG上求最長路 
164     printf("%d\n",ans);
165     return 0;
166 }

BZOJ 1924: [Sdoi2010]所駝門王的寶藏 題解