zoukankan      html  css  js  c++  java
  • bzoj 1924 所驼门王的宝藏

    题目大意:

    有一个r*c的矩阵,上面有n个点有宝藏

    每个有宝藏的点上都有传送门

    传送门有三种:第一种可以传到该行任意一个有宝藏的点,第二种可以传到该列任意一个有宝藏的点,第三种可以传到周围的八连块上有宝藏的点

    现在你可以在任意一个有宝藏的点开始,求你最多可以经过多少个不同的藏宝点

    每个藏宝点可以多次进入,每个传送门可以多次使用

    思路:

    很容易可以看出这个矩阵并没有什么卵用

    而此题的关键在于如何建图,建图所用数组见注释

    建完之后,可以使用tarjan算法之一的求强连通分量

    因为对于每个强连通分量,只要到达任意一个点,就可以到达其余所有点

    然后我们缩点,把每个强连通分量都缩为一个点

    再重新建图

    这样图就会变成DAG,然后求一下最长链并统计每一个强连通分量内有几个点就好了

      1 #include<iostream>
      2 #include<cstdio>
      3 #include<cmath>
      4 #include<algorithm>
      5 #include<cstring>
      6 #include<cstdlib>
      7 #include<queue>
      8 #include<vector>
      9 #include<stack>
     10 #include<set>
     11 #include<map>
     12 #define inf 2147483611
     13 #define ll long long
     14 #define MAXN 101001
     15 using namespace std;
     16 inline int read()
     17 {
     18     int x=0,f=1;
     19     char ch;ch=getchar();
     20     while(!isdigit(ch)) {if(ch=='-') f=-1;ch=getchar();}
     21     while(isdigit(ch)) {x=x*10+ch-'0';ch=getchar();}
     22     return x*f;
     23 }
     24 int dx[8]={1,1,1,-1,-1,-1,0,0},dy[8]={1,0,-1,1,0,-1,1,-1};//八连块用数组 
     25 map <int,int> m[10*MAXN];//记录每个位置是否有藏宝点,因为数组开不下只能用map 
     26 vector <int> vr[10*MAXN],vc[10*MAXN];//记录每行每列所有藏宝点,用vector方便记录 
     27 int n,r,c;
     28 int x[MAXN],y[MAXN];//记录每个点的横纵坐标 
     29 short t[MAXN];//记录每个点的传送门种类 
     30 int to[10*MAXN],next[10*MAXN],first[MAXN],cnt;//第一次图用邻接表 
     31 int to0[10*MAXN],next0[10*MAXN],first0[MAXN];//DAG第二次图用邻接表 
     32 int low[MAXN],dfn[MAXN],stp,scc,now,st[MAXN],top;//tarjan用数组
     33 //scc记录一共有多少强连通分量,stp记录步数,st、top记录栈 
     34 int num[MAXN],blg[MAXN];//num记录每个强连通分量中有多少个点,blg记录每个点属于那个强连通分量 
     35 int deep[MAXN];//求最长链用,记录每个强连通分量能延伸的最长长度 
     36 int ans;
     37 bool vis[MAXN];//第一次为tarjan用,第二次求最长链用 
     38 void add(int u,int v)//第一次建图 
     39 {
     40     if(u==v) return ;
     41     to[++cnt]=v,next[cnt]=first[u],first[u]=cnt;
     42 }
     43 void ADD(int u,int v) {to0[++cnt]=v,next0[cnt]=first0[u],first0[u]=cnt;}//第二次建图 
     44 void build()//第一次建图 
     45 {
     46     int tmp,s;
     47     for(int i=1;i<=r;i++)//同一行的藏宝图 
     48     {
     49         tmp=0,s=vr[i].size();
     50         for(int j=0;j<s;j++) if(t[vr[i][j]]==1) {tmp=vr[i][j];break;}
     51         for(int j=0;j<s;j++)
     52         {
     53             add(tmp,vr[i][j]);
     54             if(t[vr[i][j]]==1) add(vr[i][j],tmp);//不用连所有边,只需要这样就可以满足要求 
     55         }
     56     }
     57     for(int i=1;i<=c;i++)//同一列,方法同上 
     58     {
     59         tmp=0,s=vc[i].size();
     60         for(int j=0;j<s;j++) if(t[vc[i][j]]==2) {tmp=vc[i][j];break;}
     61         for(int j=0;j<s;j++)
     62         {
     63             add(tmp,vc[i][j]);
     64             if(t[vc[i][j]]==2) add(vc[i][j],tmp);
     65         }
     66     }
     67     for(int i=1;i<=n;i++)//八连块 
     68         if(t[i]==3)
     69             for(int j=0;j<8;j++) if(m[x[i]+dx[j]][y[i]+dy[j]]) add(i,m[x[i]+dx[j]][y[i]+dy[j]]);
     70 }
     71 void tarjan(int x)//tarjan求强连通分量 
     72 {
     73     low[x]=dfn[x]=++stp;
     74     st[++top]=x;vis[x]=1;
     75     for(int i=first[x];i;i=next[i])
     76         if(!dfn[to[i]])
     77             {tarjan(to[i]);low[x]=min(low[x],low[to[i]]);}//在栈外且未被访问过 
     78         else if(vis[to[i]]) low[x]=min(low[x],dfn[to[i]]);//在栈内 
     79     if(low[x]==dfn[x])
     80     {
     81         scc++;now=0;
     82         while(now!=x)
     83         {
     84             now=st[top--];vis[now]=0;
     85             blg[now]=scc;num[scc]++;
     86         }
     87     }
     88 }
     89 void BUILD()//第二次建图 
     90 {
     91     for(int i=1;i<=n;i++)
     92         for(int j=first[i];j;j=next[j])
     93             if(blg[i]!=blg[to[j]]) ADD(blg[i],blg[to[j]]);
     94 }
     95 void dp(int x)//求最长链 
     96 {
     97     vis[x]=1;
     98     for(int i=first0[x];i;i=next0[i])
     99     {
    100         if(!vis[to0[i]]) dp(to0[i]);
    101         deep[x]=max(deep[x],deep[to0[i]]);//延伸 
    102     }
    103     deep[x]+=num[x];
    104     ans=max(ans,deep[x]);
    105 }
    106 int main()
    107 {
    108     n=read(),r=read(),c=read();
    109     for(int i=1;i<=n;i++)
    110     {
    111         x[i]=read(),y[i]=read(),t[i]=read();
    112         m[x[i]][y[i]]=i;
    113         vr[x[i]].push_back(i);
    114         vc[y[i]].push_back(i);
    115     }
    116     build();
    117     for(int i=1;i<=n;i++)
    118         if(!dfn[i]) tarjan(i);
    119     cnt=0;
    120     BUILD();
    121     for(int i=1;i<=scc;i++)
    122         if(!vis[i]) dp(i);
    123     printf("%d",ans);
    124 }
    View Code
  • 相关阅读:
    bzoj 1697: [Usaco2007 Feb]Cow Sorting牛排序【置换群】
    【20】AngularJS 参考手册
    【19】AngularJS 应用
    【18】AngularJS 包含
    【17】AngularJS Bootstrap
    【16】AngularJS API
    【15】AngularJS 输入验证
    【14】AngularJS 表单
    【13】AngularJS 模块
    【12】AngularJS 事件
  • 原文地址:https://www.cnblogs.com/yyc-jack-0920/p/7617320.html
Copyright © 2011-2022 走看看