【BZOJ-1924】所驼门王的宝藏 Tarjan缩点(+拓扑排序) + 拓扑图DP
1924: [Sdoi2010]所驼门王的宝藏
Time Limit: 5 Sec Memory Limit: 128 MBSubmit: 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
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题卡时卡内存是什么意思??
——It's a lonely path. Don't make it any lonelier than it has to be.