题文:https://vjudge.net/problem/UVA-11324
题解:
这个题目首先可以发现,只要是一个强连通分量,要么都选,要么都不选,将点权看成强连通分量的点数,所以这个题目就转化成了DAG上的最大路。
稍微dp一下就好了。
代码:
#include <cstdio> #include <iostream> #include <algorithm> #include <cstring> #include <cmath> #include <iostream> #include <stack> #define MAXN 50100 using namespace std; struct edge{ int first; int next; int to; }a[MAXN*2]; int dfn[MAXN],in[MAXN],low[MAXN],fa[MAXN],size[MAXN]; int dp[MAXN],b[MAXN],x[MAXN],y[MAXN]; int n,m,num1=0,num2=0,num3=0; stack<int> s; void cl(){ memset(low,0,sizeof(low)); memset(dp,0,sizeof(dp)); memset(dfn,0,sizeof(dfn)); memset(fa,0,sizeof(fa)); memset(size,0,sizeof(size)); memset(a,0,sizeof(a));num1=num2=num3=0; memset(in,0,sizeof(in)); memset(b,0,sizeof(b)); memset(x,0,sizeof(x)); memset(y,0,sizeof(y)); } void addedge(int from,int to){ a[++num1].to=to; a[num1].next=a[from].first; a[from].first=num1; } void init(){ scanf("%d%d",&n,&m); for(int i=1;i<=m;i++){ scanf("%d%d",&x[i],&y[i]); addedge(x[i],y[i]); } } void tarjian(int now){ s.push(now);in[now]=1; dfn[now]=low[now]=++num3; for(int i=a[now].first;i;i=a[i].next){ int to=a[i].to; if(!dfn[to]){ tarjian(to); low[now]=min(low[now],low[to]); } else if(in[to]) low[now]=min(low[now],dfn[to]); } if(low[now]==dfn[now]){ int u=-1; num2++; while(u!=now){ u=s.top();s.pop();in[u]=0; fa[u]=num2; size[num2]++; } } } void make(){ memset(a,0,sizeof(a));num1=0; for(int i=1;i<=m;i++){ if(fa[x[i]]!=fa[y[i]]) addedge(fa[x[i]],fa[y[i]]); } } void pre(){ while(!s.empty()) s.pop(); for(int i=1;i<=n;i++) if(!dfn[i]) tarjian(i); make(); } int DP(int now){ if(b[now]) return dp[now]; b[now]=1; dp[now]+=size[now]; for(int i=a[now].first;i;i=a[i].next){ int to=a[i].to; dp[now]=max(dp[now],size[now]+DP(to)); } return dp[now]; } int main() { int t;cin>>t; while(t--){ cl(); init(); pre(); for(int i=1;i<=n;i++) DP(i); int ans=0; for(int i=1;i<=n;i++) ans=max(ans,dp[i]); printf("%d ",ans); } return 0; }