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是这个家族的领袖,外人也称其为"所驼门王". ...
随机推荐
- ajax中文乱码解决(java)
方法1: 页面端发出的数据做一次encodeURI,服务器端使用new String(old.getBytes("iso8859-1"), "utf-8") 方 ...
- odoo 权限配置讲解
今天来讲解一下odoo权限配置的简单讲解,配合公司开发的权限模块的使用,进行odoo权限配置的说明 BaseSecurityExtend 2.0模块 这是公司自主开发的一款针对odoo菜单级别进行可视 ...
- 58. Spring Boot国际化(i18n)【从零开始学Spring Boot】
国际化(internationalization)是设计和制造容易适应不同区域要求的产品的一种方式.它要求从产品中抽离所有地域语言,国家/地区和文化相关的元素.换言之,应用程序的功能和代码设计考虑在不 ...
- HDU-5583-Kingdom of Black and White(2015ACM/ICPC亚洲区上海站-重现赛)
Kingdom of Black and White ...
- hdu 3697 贪心
#include<stdio.h> #include<stdlib.h> #include<string.h> #define inf 0x3fffffff #de ...
- idea导入(import)项目和打开(open)项目的区别
前言: 每次接手老项目,都得从git或svn下载下来,但是如果之前的项目不是用idea写的怎么办,可是你又习惯啦idea,那你必须把项目在idea上跑起来,那是用import还是用open呢,如何抉择 ...
- 【springmvc】传值的几种方式&&postman接口测试
最近在用postman测试postman接口,对于springmvc传值这一块,测试了几种常用方式,总结一下.对于postman这个工具的使用也增加了了解.postman测试很棒,有了工具,测试接口, ...
- 如何爬取可用的IP代理
上一篇说到对付反爬虫有一个很关键的方法就是使用IP代理,那么我们应该如何获取这些可用的IP代理呢?这里分享一下自己这两天的一些爬取IP代理的心得体会. 1 步骤 1.找到几个提供免费IP代理的网站,获 ...
- python基础之-字符串
字符模块:strstr.strip():去掉字符串前后空格str.lstrip():去掉字符串左侧空格str.rstrip():去掉字符串右侧空格str.encode():将字符串编码为二进制str. ...
- C++ fill 和memset
以下内容来自www.cplusplus.com--------------------------------------------------- FILL: template <class ...