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

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

Time Limit: 5 Sec  Memory Limit: 128 MB
Submit: 787  Solved: 318
[Submit][Status][Discuss]

Description

Input

第一行给出三个正整数 N, R, C。 以下 N 行,每行给出一扇传送门的信息,包含三个正整数xi, yi, Ti,表示该传送门设在位于第 xi行第yi列的藏宝宫室,类型为 Ti。Ti是一个1~3间的整数, 1表示可以传送到第 xi行任意一列的“横天门”,2表示可以传送到任意一行第 yi列的“纵寰门”,3表示可以传送到周围 8格宫室的“自 由门”。 保证 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

HINT

测试点编号 N R C 1 16 20 20 2 300 1,000 1,000 3 500 100,000 100,000 4 2,500 5,000 5,000 5 50,000 5,000 5,000 6 50,000 1,000,000 1,000,000 7 80,000 1,000,000 1,000,000 8 100,000 1,000,000 1,000,000 9 100,000 1,000,000 1,000,000 10 100,000 1,000,000 1,000,000

Source

Solution

题目并不难.

很显然Tarjan缩点,重构图,然后在DAG上做DP,或者跑最长路

麻烦的在于建图....

需要用vector存在同一行上的格点,同一列上的格点,用map记录点的八连通,然后连边

连边的方式有技巧,选一个横/竖格,对同行同列的所有点连单向边,对横/竖格连双向;八连通的直接连就好

如果暴力连边,可能会出现一组WA的情况,可能需要再进行一遍拓扑排序

Code

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<vector>
#include<map>
#include<algorithm>
using namespace std;
int read()
{
    int x=0,f=1; char ch=getchar();
    while (ch<'0' || ch>'9') {if (ch=='-') f=-1; ch=getchar();}
    while (ch>='0' && ch<='9') {x=x*10+ch-'0'; ch=getchar();}
    return x*f;
}
#define maxn 100010
int dx[8]={0,0,1,1,1,-1,-1,-1},dy[8]={1,-1,0,1,-1,0,1,-1};
struct EdgeNode{int next,to;}edge[maxn*10],road[maxn*10];
int cnt,tot,head[maxn],last[maxn];
void addedge(int u,int v) {cnt++; edge[cnt].next=head[u]; head[u]=cnt; edge[cnt].to=v;}
void insertedge(int u,int v) {if (u==v) return; addedge(u,v);}
void addroad(int u,int v) {tot++; road[tot].next=last[u]; last[u]=tot; road[tot].to=v;}
void insertroad(int u,int v) {addroad(u,v);}
int x[maxn],y[maxn],t[maxn],dfn[maxn],low[maxn],stack[maxn],num[maxn],belong[maxn],dp[maxn];
bool visit[maxn];
int n,r,c,ans,top,qcnt;
vector<int>h[maxn*10],l[maxn*10];
map<int,int>mp[maxn*10];
void BuildGraph()
{
    for (int i=1; i<=r; i++) 
        {    
            int hn=h[i].size(),now=0;
            for (int j=0; j<=hn-1; j++) if (t[h[i][j]]==1) {now=h[i][j]; break;}
            for (int j=0; j<=hn-1; j++) {insertedge(now,h[i][j]); if (t[h[i][j]]==1) insertedge(h[i][j],now);}
        }
    for (int i=1; i<=c; i++)
        {
            int ln=l[i].size(),now=0;
            for (int j=0; j<=ln-1; j++) if (t[l[i][j]]==2) {now=l[i][j]; break;}
            for (int j=0; j<=ln-1; j++) {insertedge(now,l[i][j]); if (t[l[i][j]]==2) insertedge(l[i][j],now);}
        }
    for (int i=1; i<=n; i++)
        if (t[i]==3)
            for (int xx,yy,j=0; j<=7; j++)
                {
                    xx=x[i]+dx[j],yy=y[i]+dy[j];
                    if (mp[xx][yy]) insertedge(i,mp[xx][yy]);
                }
}
void Tarjan(int x) 
{ 
    dfn[x]=low[x]=++tot; visit[x]=1; stack[++top]=x; 
    for (int i=head[x]; i; i=edge[i].next) 
        { 
            if (!dfn[edge[i].to]) 
                { 
                    Tarjan(edge[i].to); 
                    if (low[edge[i].to]<low[x]) low[x]=low[edge[i].to]; 
                } 
            else 
                if(visit[edge[i].to] && dfn[edge[i].to]<low[x]) 
                    low[x]=dfn[edge[i].to]; 
        }
    if (dfn[x]==low[x]) 
        { 
            int uu=0; qcnt++; 
            while (x!=uu) 
                uu=stack[top--],num[qcnt]++,visit[uu]=0,belong[uu]=qcnt;  
        } 
} 
void reBuildGraph()
{
    for (int i=1; i<=n; i++) 
        for (int j=head[i]; j; j=edge[j].next) 
            if (belong[i]!=belong[edge[j].to]) 
                insertroad(belong[i],belong[edge[j].to]); 
}
void DP(int now)
{
    visit[now]=1;
    for (int i=last[now]; i; i=road[i].next)
        {
            if (!visit[road[i].to]) DP(road[i].to);
            dp[now]=max(dp[now],dp[road[i].to]);
        }
    dp[now]+=num[now];
    ans=max(ans,dp[now]);
}
int main()
{
    n=read(); r=read(); c=read();
    for (int i=1; i<=n; i++)
        {
            x[i]=read(),y[i]=read(),t[i]=read();
            mp[x[i]][y[i]]=i; h[x[i]].push_back(i); l[y[i]].push_back(i);
        }
    BuildGraph();
    for (int i=1; i<=n; i++) if (!dfn[i]) Tarjan(i);
    reBuildGraph();
    for (int i=1; i<=qcnt; i++) if (!visit[i]) DP(i);
    printf("%d\n",ans); 
    return 0;
}

shabi题卡时卡内存是什么意思??

posted @ 2016-06-03 22:14  DaD3zZ  阅读(712)  评论(0编辑  收藏  举报