鉴于Uva比较难上……
有一张有向图G,求一个结点数最大的结点集,使得该结点集中任意两个节点u和v满足要么u能到v,要么v能到u(可以互相到达)。
首先求强联通分量,因为同一个强联通分量里的点要么都选要么都不选……
然后缩点得到一个有向无环图(DAG)。。
令收缩后的点具有一个点权,代表这个SCC(强联通分量)原来的结点数。。
然后动态规划求最长路即可。
这题真是cs。。。
我拓扑排序排炸了……(不要问我为什么不用记忆化搜索,因为我不会拓扑排序- -)
我怕重边会影响求拓扑排序序列,于是写成了这样:
inline void topoSort(){
stack<int>s;
bool visit[maxn];
for(int i=1;i<=sccCnt;++i)
if(!in[i])s.push(i);
while(!s.empty()){
int x=s.top();s.pop();
q[++tail]=x;
CLR(visit);
for(int k=list[x+n];k;k=next[k]){
--in[to[k]-n];
if(!visit[to[k]-n])
if(!in[to[k]-n]) s.push(to[k]-n);
visit[to[k]-n]=true;
}
}
}
}
但是这样会造成一个问题:如果遍历邻接表时遍历到了同一个点(因为重边),
那么前一次访问的时候将进入12行的if中去,这时in不为0,所以不入栈;
但是等到那个点的in变成0了,他就有可能不进栈了!!!!
真是too young too naive。
#include<cstring>
#include<iostream>
#include<cstdio>
#include<stack>
using namespace std;
const int maxn=1001<<1,maxm=50001<<2;
int list[maxn],next[maxm],to[maxm];
int sccno[maxn],pre[maxn],lowlink[maxn],in[maxn],dis[maxn],w[maxn];
int q[maxn],tail,tot,n,m,dfsClk,sccCnt;
stack<int>s;
#define CLR(x) memset(x,0,sizeof x)
inline void init(){
tot=dfsClk=sccCnt=tail=0;
CLR(list);CLR(sccno);CLR(pre);CLR(lowlink);
CLR(in);CLR(dis);CLR(w);
while(!s.empty())s.pop();
}
void dfs(int u){
pre[u]=lowlink[u]=++dfsClk;
s.push(u);
for(int k=list[u];k;k=next[k]){
int v=to[k];
if(!pre[v]){
dfs(v);
lowlink[u]=min(lowlink[u],lowlink[v]);
}
else if(!sccno[v]){
lowlink[u]=min(lowlink[u],pre[v]);
}
}
if(lowlink[u]==pre[u]){
++sccCnt;
for(;;){
int x=s.top();s.pop();
sccno[x]=sccCnt;
w[sccCnt]++;
if(x==u) break;
}
}
}
inline void add(int a,int b){
next[++tot]=list[a];
list[a]=tot;
to[tot]=b;
}
inline void topoSort(){
stack<int>s;
bool visit[maxn];//=false;
for(int i=1;i<=sccCnt;++i)
if(!in[i])s.push(i);
while(!s.empty()){
int x=s.top();s.pop();
q[++tail]=x;//!!!!!!!!!!
// cout<<"x="<<x<<"\n";
CLR(visit);
for(int k=list[x+n];k;k=next[k]){
// cout<<to[k]-n<<"]\n";
--in[to[k]-n];
if(!in[to[k]-n]) s.push(to[k]-n);
// visit[to[k]-n]=true;
// }
}
}
}
inline void Unique(){
bool visit[maxn]={false};
for(int i=1+n;i<=sccCnt+n;++i){
CLR(visit);
for(int k=list[i];k;k=next[k]){
if(!visit[to[k]-n]){
visit[to[k]-n]=true;
add(i+n,to[k]+n);
in[i-n]++;
}
}
}
}
inline int read(){int x=0;scanf("%d",&x);return x;}
int main(){
int T=read();
while(T--){
init();
n=read(),m=read();
for(int i=1;i<=m;++i){
int a=read(),b=read();
add(a,b);
}
for(int i=1;i<=n;++i)
if(!pre[i]) dfs(i);
for(int i=1;i<=n;++i){
for(int k=list[i];k;k=next[k]){
if(sccno[i]!=sccno[to[k]])
in[sccno[to[k]]]++,add(sccno[i]+n,sccno[to[k]]+n);
}
}
topoSort();
int ans=0;
for(int i=tail;i;--i){
for(int k=list[q[i]+n];k;k=next[k])
dis[q[i]]=max(dis[q[i]],dis[to[k]-n]);
dis[q[i]]+=w[q[i]];
}
for(int i=1;i<=sccCnt;++i) ans=max(ans,dis[i]);
printf("%d\n",ans);
}
}