bzoj 1924 [Sdoi2010]所驼门王的宝藏(构图,SCC,DP)
Description
Input
第一行给出三个正整数 N, R, C。 以下 N 行,每行给出一扇传送门的信息,包含三个正整数xi, yi, Ti,表示该传送门设在位于第 xi行第yi列的藏宝宫室,类型为 Ti。Ti是一个1~3间的整数, 1表示可以传送到第 xi行任意一列的“横天门”,2表示可以传送到任意一行第 yi列的“纵寰门”,3表示可以传送到周围 8格宫室的“ziyoumen”。 保证 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
【思路】
构图,SCC,DP
因为只有宝藏室有门所以传送到空房间是没有意义的,这样可以将n个宝藏室构图。
求出SCC,对于一个SCC内的任意节点可以互相到达而到达次数没有限制,所以缩点,将点权设为SCC的结点数,这样问题就变成了求DAG上的一条最大点权路,可以用DP求解。
需要注意的是DAG不一定连通。
【代码】
1 #include<set> 2 #include<stack> 3 #include<vector> 4 #include<cstdio> 5 #include<cstring> 6 #include<iostream> 7 #include<algorithm> 8 #define FOR(a,b,c) for(int a=(b);a<=(c);a++) 9 using namespace std; 10 11 const int N = 2*1e5+10; 12 struct Node{ 13 int x,y,id; 14 bool operator < (const Node& rhs) const{ 15 return x<rhs.x || (x==rhs.x&&y<rhs.y); 16 } 17 }; 18 void read(int& x) { 19 char c=getchar(); int f=1; x=0; 20 while(!isdigit(c)) {if(c=='-')f=-1; c=getchar();} 21 while(isdigit(c)) x=x*10+c-'0',c=getchar(); 22 x*=f; 23 } 24 int n,R,C,val[N],f[N],x[N],y[N],z[N],in[N]; 25 vector<int> g[N],G[N],quex[N],quey[N]; 26 int dfsc,pre[N],lowlink[N],sccno[N],scccnt; 27 stack<int> S; set<Node> xy; 28 29 void dfs(int u) { 30 pre[u]=lowlink[u]=++dfsc; 31 S.push(u); 32 FOR(i,0,(int)g[u].size()-1) { 33 int v=g[u][i]; 34 if(!pre[v]) { 35 dfs(v); 36 lowlink[u]=min(lowlink[u],lowlink[v]); 37 } 38 else if(!sccno[v]) { 39 lowlink[u]=min(lowlink[u],pre[v]); 40 } 41 } 42 if(lowlink[u]==pre[u]) { 43 ++scccnt; 44 for(;;) { 45 int x=S.top(); S.pop(); 46 sccno[x]=scccnt; 47 if(x==u) break; 48 } 49 } 50 } 51 52 int dp(int u) { 53 int& ans=f[u]; 54 if(ans) return ans; 55 FOR(i,0,(int)G[u].size()-1) 56 ans=max(ans,dp(G[u][i])); 57 ans+=val[u]; 58 return ans; 59 } 60 61 void get_graph() { 62 FOR(i,1,n) { 63 read(x[i]),read(y[i]),read(z[i]); 64 quex[x[i]].push_back(i),quey[y[i]].push_back(i); 65 xy.insert((Node){x[i],y[i],i}); 66 } 67 FOR(i,1,n) { 68 if(z[i]==1) { 69 FOR(j,0,(int)quex[x[i]].size()-1) 70 if(i!=quex[x[i]][j]) g[i].push_back(quex[x[i]][j]); 71 } 72 else if(z[i]==2) { 73 FOR(j,0,(int)quey[y[i]].size()-1) 74 if(i!=quey[y[i]][j]) g[i].push_back(quey[y[i]][j]); 75 } else { 76 FOR(dx,-1,1) FOR(dy,-1,1) if(dx!=0||dy!=0) { 77 int xx=x[i]+dx,yy=y[i]+dy; 78 Node u=*xy.find((Node){xx,yy,0}); 79 if(u.x==xx&&u.y==yy) g[i].push_back(u.id); 80 } 81 } 82 } 83 } 84 85 int main() { 86 //freopen("in.in","r",stdin); 87 //freopen("out.out","w",stdout); 88 read(n),read(R),read(C); 89 get_graph(); 90 FOR(i,1,n) if(!pre[i]) dfs(i); 91 FOR(u,1,n) { 92 val[sccno[u]]++; 93 FOR(j,0,(int)g[u].size()-1) { 94 int v=g[u][j]; 95 if(sccno[v]!=sccno[u]) { 96 in[sccno[v]]++; 97 G[sccno[u]].push_back(sccno[v]); 98 } 99 } 100 } 101 int ans=0; 102 FOR(i,1,scccnt) 103 if(!in[i]) ans=max(ans,dp(i)); 104 printf("%d\n",ans); 105 }
ps:万万没想到,bokeyuan竟然和谐free gate
posted on 2016-02-27 10:54 hahalidaxin 阅读(249) 评论(0) 编辑 收藏 举报