bzoj 1924 所驼门王的宝藏
题目大意:
有一个r*c的矩阵,上面有n个点有宝藏
每个有宝藏的点上都有传送门
传送门有三种:第一种可以传到该行任意一个有宝藏的点,第二种可以传到该列任意一个有宝藏的点,第三种可以传到周围的八连块上有宝藏的点
现在你可以在任意一个有宝藏的点开始,求你最多可以经过多少个不同的藏宝点
每个藏宝点可以多次进入,每个传送门可以多次使用
思路:
很容易可以看出这个矩阵并没有什么卵用
而此题的关键在于如何建图,建图所用数组见注释
建完之后,可以使用tarjan算法之一的求强连通分量
因为对于每个强连通分量,只要到达任意一个点,就可以到达其余所有点
然后我们缩点,把每个强连通分量都缩为一个点
再重新建图
这样图就会变成DAG,然后求一下最长链并统计每一个强连通分量内有几个点就好了
#include<iostream>
#include<cstdio>
#include<cmath>
#include<algorithm>
#include<cstring>
#include<cstdlib>
#include<queue>
#include<vector>
#include<stack>
#include<set>
#include<map>
#define inf 2147483611
#define ll long long
#define MAXN 101001
using namespace std;
inline int read()
{
int x=,f=;
char ch;ch=getchar();
while(!isdigit(ch)) {if(ch=='-') f=-;ch=getchar();}
while(isdigit(ch)) {x=x*+ch-'';ch=getchar();}
return x*f;
}
int dx[]={,,,-,-,-,,},dy[]={,,-,,,-,,-};//八连块用数组
map <int,int> m[*MAXN];//记录每个位置是否有藏宝点,因为数组开不下只能用map
vector <int> vr[*MAXN],vc[*MAXN];//记录每行每列所有藏宝点,用vector方便记录
int n,r,c;
int x[MAXN],y[MAXN];//记录每个点的横纵坐标
short t[MAXN];//记录每个点的传送门种类
int to[*MAXN],next[*MAXN],first[MAXN],cnt;//第一次图用邻接表
int to0[*MAXN],next0[*MAXN],first0[MAXN];//DAG第二次图用邻接表
int low[MAXN],dfn[MAXN],stp,scc,now,st[MAXN],top;//tarjan用数组
//scc记录一共有多少强连通分量,stp记录步数,st、top记录栈
int num[MAXN],blg[MAXN];//num记录每个强连通分量中有多少个点,blg记录每个点属于那个强连通分量
int deep[MAXN];//求最长链用,记录每个强连通分量能延伸的最长长度
int ans;
bool vis[MAXN];//第一次为tarjan用,第二次求最长链用
void add(int u,int v)//第一次建图
{
if(u==v) return ;
to[++cnt]=v,next[cnt]=first[u],first[u]=cnt;
}
void ADD(int u,int v) {to0[++cnt]=v,next0[cnt]=first0[u],first0[u]=cnt;}//第二次建图
void build()//第一次建图
{
int tmp,s;
for(int i=;i<=r;i++)//同一行的藏宝图
{
tmp=,s=vr[i].size();
for(int j=;j<s;j++) if(t[vr[i][j]]==) {tmp=vr[i][j];break;}
for(int j=;j<s;j++)
{
add(tmp,vr[i][j]);
if(t[vr[i][j]]==) add(vr[i][j],tmp);//不用连所有边,只需要这样就可以满足要求
}
}
for(int i=;i<=c;i++)//同一列,方法同上
{
tmp=,s=vc[i].size();
for(int j=;j<s;j++) if(t[vc[i][j]]==) {tmp=vc[i][j];break;}
for(int j=;j<s;j++)
{
add(tmp,vc[i][j]);
if(t[vc[i][j]]==) add(vc[i][j],tmp);
}
}
for(int i=;i<=n;i++)//八连块
if(t[i]==)
for(int j=;j<;j++) if(m[x[i]+dx[j]][y[i]+dy[j]]) add(i,m[x[i]+dx[j]][y[i]+dy[j]]);
}
void tarjan(int x)//tarjan求强连通分量
{
low[x]=dfn[x]=++stp;
st[++top]=x;vis[x]=;
for(int i=first[x];i;i=next[i])
if(!dfn[to[i]])
{tarjan(to[i]);low[x]=min(low[x],low[to[i]]);}//在栈外且未被访问过
else if(vis[to[i]]) low[x]=min(low[x],dfn[to[i]]);//在栈内
if(low[x]==dfn[x])
{
scc++;now=;
while(now!=x)
{
now=st[top--];vis[now]=;
blg[now]=scc;num[scc]++;
}
}
}
void BUILD()//第二次建图
{
for(int i=;i<=n;i++)
for(int j=first[i];j;j=next[j])
if(blg[i]!=blg[to[j]]) ADD(blg[i],blg[to[j]]);
}
void dp(int x)//求最长链
{
vis[x]=;
for(int i=first0[x];i;i=next0[i])
{
if(!vis[to0[i]]) dp(to0[i]);
deep[x]=max(deep[x],deep[to0[i]]);//延伸
}
deep[x]+=num[x];
ans=max(ans,deep[x]);
}
int main()
{
n=read(),r=read(),c=read();
for(int i=;i<=n;i++)
{
x[i]=read(),y[i]=read(),t[i]=read();
m[x[i]][y[i]]=i;
vr[x[i]].push_back(i);
vc[y[i]].push_back(i);
}
build();
for(int i=;i<=n;i++)
if(!dfn[i]) tarjan(i);
cnt=;
BUILD();
for(int i=;i<=scc;i++)
if(!vis[i]) dp(i);
printf("%d",ans);
}
bzoj 1924 所驼门王的宝藏的更多相关文章
- BZOJ 1924 所驼门王的宝藏(强连通分量缩点+DAG最长链)
思路不是很难,因为宝藏只会在给出的n个点内有,于是只需要在这n个点里面连边,一个点如果能到达另一个点则连一条有向边, 这样用强连通分量缩点后答案就是DAG的最长链. 问题在于暴力建图是O(n^2)的, ...
- [BZOJ 1924][Sdoi2010]所驼门王的宝藏
1924: [Sdoi2010]所驼门王的宝藏 Time Limit: 5 Sec Memory Limit: 128 MBSubmit: 1285 Solved: 574[Submit][Sta ...
- 【BZOJ-1924】所驼门王的宝藏 Tarjan缩点(+拓扑排序) + 拓扑图DP
1924: [Sdoi2010]所驼门王的宝藏 Time Limit: 5 Sec Memory Limit: 128 MBSubmit: 787 Solved: 318[Submit][Stat ...
- 「BZOJ1924」「SDOI2010」 所驼门王的宝藏 tarjan + dp(DAG 最长路)
「BZOJ1924」[SDOI2010] 所驼门王的宝藏 tarjan + dp(DAG 最长路) -------------------------------------------------- ...
- 8.18 NOIP模拟测试25(B) 字符串+乌鸦喝水+所驼门王的宝藏
T1 字符串 卡特兰数 设1为向(1,1)走,0为向(1,-1)走,限制就是不能超过$y=0$这条线,题意转化为从(0,0)出发,走到(n+m,n-m)且不越过$y=0$,然后就裸的卡特兰数,$ans ...
- 【题解】SDOI2010所驼门王的宝藏(强连通分量+优化建图)
[题解]SDOI2010所驼门王的宝藏(强连通分量+优化建图) 最开始我想写线段树优化建图的说,数据结构学傻了233 虽然矩阵很大,但是没什么用,真正有用的是那些关键点 考虑关键点的类型: 横走型 竖 ...
- noip模拟5[string·matrix·big·所驼门王的宝藏]
怎么说呢这一场考得还算可以呢 拿了120pts,主要是最后一个题灵光开窍,想起来是tarjan,然后勉勉强强拿了40pts,本来是可以拿满分的,害 没事考完了就要反思 这场考试我心态超好,从第一个题开 ...
- BZOJ 1924: [Sdoi2010]所驼门王的宝藏 【tarjan】
Description 在宽广的非洲荒漠中,生活着一群勤劳勇敢的羊驼家族.被族人恭称为“先 知”的Alpaca L. Sotomon 是这个家族的领袖,外人也称其为“所驼门王”.所 驼门王毕生致力于维 ...
- [SDOI2010]所驼门王的宝藏
题目描述 在宽广的非洲荒漠中,生活着一群勤劳勇敢的羊驼家族.被族人恭称为"先知"的Alpaca L. Sotomon是这个家族的领袖,外人也称其为"所驼门王". ...
随机推荐
- ORACLE数据库查看执行计划的方法
一.什么是执行计划(explain plan) 执行计划:一条查询语句在ORACLE中的执行过程或访问路径的描述. 二.如何查看执行计划 1: 在PL/SQL下按F5查看执行计划.第三方工具toad等 ...
- Node.js & Unix/Linux & NVM
Node.js & Unix/Linux & NVM nvm https://github.com/creationix/nvm https://github.com/xyz-data ...
- noip模拟赛 斐波那契
分析:暴力分有90,真良心啊. a,b这么大,连图都建不出来,肯定是有一个规律.把每个点的父节点写出来:0 1 1 12 123 12345 12345678,可以发现每一个循环的长度刚好是斐波那契数 ...
- DFS template and summary
最近一直在学习Deep Frist Search,也在leetcode上练习了不少题目.从最开始的懵懂,到现在遇到问题基本有了思路.依然清晰的记得今年2月份刚开始刷题的时做subsets的那个吃力劲, ...
- vagrant的学习 之 基础学习
vagrant的学习 之 基础学习 本文根据慕课网的视频教程练习,感谢慕课网! 慕课的参考文档地址:https://github.com/apanly/mooc/tree/master/vagrant ...
- SOJ 3531_Number Pyramids
[题意]给定一个数top及最底层元素个数n,构成一个以给top为塔尖,层数为n的如杨辉三角的金字塔,求有多少种 [分析]最终种数其实只与最底层的n个数的组合数有关,上层的每个都数是由最底层数相加得来 ...
- POJ 3279 Fliptile【枚举】
题意: 又是农夫和牛的故事...有m*n个黑白块,黑块的背面是白块,白块背面是黑块,一头牛踩一块,则这个块的上下左右的方块都会转动,问至少踩多少块,才会使所有块都变成白色? 分析: 还是开关问题,同样 ...
- css3 模拟标牌震荡效果
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <meta http ...
- 洛谷 P2033 Chessboard Dance
P2033 Chessboard Dance 题目描述 在棋盘上跳舞是件有意思的事情.现在给你一张国际象棋棋盘和棋盘上的一些子以及你的初始位置和方向.求按一定操作后,棋盘的状态. 操作有四种,描述如下 ...
- 携程Apollo(阿波罗)配置中心本地开发模式不接入配置中心进行本地开发
官方教程:https://github.com/ctripcorp/apollo/wiki/Java%E5%AE%A2%E6%88%B7%E7%AB%AF%E4%BD%BF%E7%94%A8%E6%8 ...