找最长的连接的点的数量。用tarjan缩点,思考可知每一个强连通分量里的点要么都选,要么都不选(走别的路),可以动规解决。
1 #include<iostream> 2 #include<cstdio> 3 #include<algorithm> 4 #include<vector> 5 #include<cstring> 6 using namespace std; 7 const int mxn=12000; 8 int top,stack[mxn]; 9 bool inst[mxn]; 10 int cnt,dnow; 11 int dfn[mxn],low[mxn]; 12 int belone[mxn]; 13 int ptcnt[mxn]; 14 int dp[mxn]; 15 vector<int> e[mxn];//邻接表 16 vector<int> pt[mxn];//缩点后的点集 17 void clear(){ 18 cnt=0;dnow=0;top=0; 19 memset(dfn,-1,sizeof(dfn)); 20 memset(inst,false,sizeof(inst)); 21 memset(dp,0,sizeof dp); 22 memset(ptcnt,0,sizeof ptcnt); 23 memset(belone,0,sizeof belone); 24 for(int i=1;i<mxn;i++) e[i].clear(); 25 for(int i=1;i<mxn;i++) pt[i].clear(); 26 } 27 int n,m; 28 void tarjan(int s){ 29 int v=0,i; 30 dfn[s]=++dnow; 31 low[s]=dfn[s]; 32 inst[s]=true; 33 stack[++top]=s; 34 int si=e[s].size(); 35 for(i=0;i<si;i++){ 36 v=e[s][i]; 37 if(dfn[v]==-1){ 38 tarjan(v); 39 low[s]=min(low[v],low[s]); 40 } 41 else if(inst[v]){ 42 low[s]=min(dfn[v],low[s]); 43 } 44 } 45 if(dfn[s]==low[s]){ 46 cnt++; 47 do{ 48 v=stack[top--]; 49 belone[v]=cnt; 50 inst[v]=false; 51 }while(s!=v); 52 } 53 return; 54 } 55 int find(int x){//动规 56 if(pt[x].size()==0)return dp[x]=ptcnt[x]; 57 if(dp[x])return dp[x]; 58 int mx=0; 59 for(int i=0;i<pt[x].size();i++){ 60 mx=max(mx,find(pt[x][i])); 61 } 62 dp[x]=mx+ptcnt[x]; 63 return dp[x]; 64 } 65 void solve(){//统计缩完点之后的连通情况 66 int i,j,k; 67 for(i=1;i<=n;i++){ 68 ptcnt[belone[i]]++; 69 for(j=0;j<e[i].size();j++){ 70 int v=e[i][j]; 71 if(belone[i]!=belone[v]) 72 pt[belone[i]].push_back(belone[v]); 73 } 74 } 75 int ans=0; 76 for(i=1;i<=cnt;i++)ans=max(ans,find(i)); 77 printf("%d\n",ans); 78 return; 79 } 80 int main(){ 81 int T; 82 scanf("%d",&T); 83 while(T--){ 84 scanf("%d%d",&n,&m); 85 clear(); 86 int i,j; 87 int u,v; 88 for(i=1;i<=m;i++){ 89 scanf("%d%d",&u,&v); 90 e[u].push_back(v); 91 } 92 for(i=1;i<=n;i++){//缩点 93 if(dfn[i]==-1)tarjan(i); 94 } 95 solve(); 96 } 97 return 0; 98 }
时间: 2024-10-30 00:17:39