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是这个家族的领袖,外人也称其为"所驼门王". ...
随机推荐
- Go:slice
一.切片创建方式 func main() { // 创建切片方式1 // 让切片引用一个数组 array := [...]int{1, 2, 3, 4} slice1 := array[1:3] fm ...
- 【转】vfork 和 fork的区别
fork()与vfock()都是创建一个进程,那他们有什么区别呢?总结有以下三点区别: 1. fork ():子进程拷贝父进程的数据段,代码段 vfork ( ):子进程与父进程共享数据段 ...
- 4.model 字段
一.字段名 字段名 类型 参数 AutoField(Field) - int自增列, 必须填入参数 primary_key=True BigAutoField(AutoField) - bigint自 ...
- Centos下PHP7.1打开Oracle扩展
背景 最近因为项目研究了一下PHP集成Oracle,虽然这个组合很奇葩,但万一用到请勿采坑~ 环境 CentOS Linux release 7.3.1611 (Core) PHP7.1.1 安装or ...
- MyBaties 异常之 java.lang.UnsupportedOperationException
sql语句 对应的接口为: 包错误的详情为: java.lang.UnsupportedOperationException 原因: resultType返回的是集合中的元素类型,而不是集合本身 SQ ...
- Altium designer中生成gerbera文件
在Altium designer中生成gerbera文件的方法有很多,不同版本,差异行不太大,正如下边链接地址里博主在10版本下的方法,在6.0版本长也是这样 http://blog.sina.com ...
- hadoop_exporter
1.下载安装go 1.下载二进制包:go1.4.linux-amd64.tar.gz. 2.将下载的二进制包解压至 /usr/local目录. tar -C /usr/local -xzf go1.4 ...
- C语言判断一个数能否被3和5整除
#include <stdio.h> /* 判断一个数能不能同时被3和5整除 --------soulsjie 20170525----- */ void main(){ int inpu ...
- BNUOJ 7697 Information Disturbing
Information Disturbing Time Limit: 3000ms Memory Limit: 65536KB This problem will be judged on HDU. ...
- 添物零基础到架构师(基础篇) - JavaScript
JavaScript是什么? JavaScript是web开发必须学习的,ECMAScript是其规则来源. JavaScript的历史 Developed by Brendan Eich of Ne ...