BZOJ 1924: [Sdoi2010]所驼门王的宝藏 题解

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了BZOJ 1924: [Sdoi2010]所驼门王的宝藏 题解相关的知识,希望对你有一定的参考价值。

此文为博主原创题解,转载时请通知博主,并把原文链接放在正文醒目位置。

题目链接: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]所驼门王的宝藏 题解的主要内容,如果未能解决你的问题,请参考以下文章

BZOJ 1924: [Sdoi2010]所驼门王的宝藏 题解

BZOJ:1924: [Sdoi2010]所驼门王的宝藏

bzoj 1924: [Sdoi2010]所驼门王的宝藏

bzoj1924: [Sdoi2010]所驼门王的宝藏

BZOJ 1924 Sdoi2010 所驼门的宝藏

BZOJ-1924所驼门王的宝藏 Tarjan缩点(+拓扑排序) + 拓扑图DP