Tarjan水题系列(3):HNOI2006 潘多拉的魔盒
题目:
大意:
盒子与盒子之间的关系构成一个有向图 求图上包含节点数最多的路径的节点数
思路:
有向图上求包含节点数最多的路径的节点数 可直接使用tarjan缩点后拓扑dp求得 在此不赘述
此题重点是如何判定盒子与盒子之间的关系
首先我们要有一个共识 盒子的起点一致 一个盒子包含另一个盒子相当于它可以走另一个盒子到不了的路 换句话说 一个盒子不是另一个盒子的下属当且仅当它能够到另外一个盒子走不到的地方
而与此同时此题的数据范围非常的小 所以我们可以有一点大胆的想法
判定两只笔谁真谁伪 我们可以判断写同一个字的表现来看 许多实验检验某一物的某一性质是否相同的原理都基本含有对照的思想
我们在这里也可以如此 两个盒子同时从起点出发 同时走一样的路径 走到谁不能走或双方走完为止(边全遍历完) 通过这样便可以判断盒子之间的关系
同时注意这里的判断是单向的即i属于不属于j 并没有判断j属不属于i所以两种情况都要考虑
至此算法也已经很明显了
下面是代码
#include <cstdio> #include <iostream> #include <algorithm> #include <memory.h> #include <queue> #define MAXX 55 #define r(x) x=read() using namespace std; int lj[MAXX][MAXX][3],map[MAXX][MAXX],put[MAXX][MAXX],flag[MAXX][MAXX], id[MAXX],sta[MAXX],dfn[MAXX],low[MAXX],dp[MAXX],w[MAXX], pre[MAXX],flag2[MAXX],ans,top,k,num,n; int h[MAXX],cnt; struct edge{int to,nex;}e[MAXX]; void add(int u,int to) { cnt++; e[cnt]=(edge){to,h[u]}; h[u]=cnt; } typedef pair<int ,int >node; void tarjan(int now) { low[now]=dfn[now]=++k; sta[++top]=now; for(int i=h[now];i;i=e[i].nex) { if(!dfn[e[i].to]) tarjan(e[i].to),low[now]=min(low[now],low[e[i].to]); else if(!id[e[i].to]) low[now]=min(low[now],dfn[e[i].to]); } if(dfn[now]==low[now]) { id[now]=++num; while(sta[top]!=now){id[sta[top]]=num,--top;} --top; } } bool bfs(int x,int y) { memset(flag,0,sizeof(flag)); queue<node>que; que.push(node(0,0)); while(!que.empty()) { node p; p=que.front();que.pop(); for(int i=0;i<=1;++i) { int x1=lj[x][p.first][i],y1=lj[y][p.second][i]; if(put[x][x1]&&!put[y][y1]) return 0; else if(!flag[x1][y1]) que.push(node(x1,y1)),flag[x1][y1]=1; } } return 1; } int read() { char ch=0;int w=0; while(ch<'0'||ch>'9'){ch=getchar();} while(ch>='0'&&ch<='9'){w=w*10+ch-'0';ch=getchar();} return w; } int main() { r(n); for(int t=1;t<=n;++t) { int n1=0,nm=0,to=0; r(n1),r(nm); for(int i=1;i<=nm;++i) r(to),put[t][to]=1; for(int i=0;i<n1;++i) for(int j=0;j<=1;++j) r(to),lj[t][i][j]=to; } for(int i=1;i<=n;++i) for(int j=1;j<=n;++j) if(i!=j&&bfs(i,j)) add(i,j); for(int i=1;i<=n;++i) if(!id[i]) tarjan(i); for(int i=1;i<=n;++i) { w[id[i]]+=1; for(int j=h[i];j;j=e[j].nex) if(id[i]!=id[e[j].to]) map[id[i]][id[e[j].to]]=1,++pre[id[e[j].to]]; } queue<int>que; for(int i=1;i<=num;++i) if(!pre[i]) que.push(i),dp[i]=w[i],ans=max(dp[i],ans); while(!que.empty()) { int p=que.front();que.pop(); for(int i=1;i<=num;++i) if(map[p][i]) { dp[i]=max(dp[i],dp[p]+w[i]),ans=max(dp[i],ans); if(!flag2[i]) que.push(i),flag2[i]=1; } flag2[p]=0; } printf("%d",ans); return 0; }