bzoj 1093 最大半连通子图
这个题一定要把题意弄清楚,然后就是发现可以缩点搞,缩点了以后这个最大半连通子图就是一条最长的单向链。
然后用类似树型dp的方法(这里是BFS更新答案),可以把答案求出来。
注意缩点以后可能会有重边(参考proverbs大神的博客)如果用DFS更新dp的话,不好判断重边。
View Code
1 #include<iostream> 2 #include<cstdio> 3 #include<algorithm> 4 #include<cmath> 5 #include<cstring> 6 #define maxn 120000 7 #define maxm 1200000 8 #define inf 2147483646 9 using namespace std; 10 struct et 11 { 12 int s,t,next; 13 }d[maxm],e[maxm]; 14 int f[maxn],g[maxn]; 15 int dfn[maxn],low[maxn],web[maxn],sum[maxn],q[maxn]; 16 int fir[maxn],last[maxn],v[maxn],id[maxn],stack[maxn],vis[maxn]; 17 int n,m,tot,tt,num,ms,tim,top; 18 19 inline void insert(int x,int y) 20 { 21 e[++tot].s=x; e[tot].t=y; e[tot].next=fir[x]; fir[x]=tot; 22 } 23 inline void add(int x,int y) 24 { 25 d[++tt].s=x; d[tt].t=y; d[tt].next=last[x]; last[x]=tt; 26 } 27 28 inline void tarjan(int now) 29 { 30 dfn[now]=low[now]=++tim; 31 stack[++top]=now; 32 v[now]=1; 33 for (int j=last[now];j;j=d[j].next) 34 { 35 int k=d[j].t; 36 if (!v[k]) tarjan(k); 37 if (v[k]<2) low[now]=min(low[now],low[k]); 38 } 39 if (dfn[now]==low[now]) 40 { 41 num++; 42 while (stack[top+1]!=now) 43 { 44 v[stack[top]]=2; 45 web[stack[top]]=num; 46 sum[num]++; 47 --top; 48 } 49 } 50 } 51 52 inline void dfs(int now) 53 { 54 v[now]=1; 55 for (int j=last[now];j;j=d[j].next) 56 { 57 int k=d[j].t; 58 if (web[now]!=web[k]) insert(web[now],web[k]),++id[web[k]]; 59 if (!v[k]) dfs(k); 60 } 61 } 62 63 inline void find() 64 { 65 memset(vis,0,sizeof(vis)); 66 int head=0,tail=0; 67 for (int i=1;i<=num;i++) 68 if (!id[i]) q[++tail]=i,f[i]=sum[i],g[i]=1; 69 while (head<tail) 70 { 71 int now=q[++head]; 72 for (int j=fir[now];j;j=e[j].next) 73 { 74 int k=e[j].t; 75 if (!(--id[k])) q[++tail]=k; 76 if (vis[k]==now) continue; 77 if (f[now]+sum[k]>f[k]) f[k]=f[now]+sum[k],g[k]=g[now]; 78 else 79 if (f[now]+sum[k]==f[k]) g[k]=(g[k]+g[now])%ms; 80 vis[k]=now; 81 } 82 } 83 } 84 85 int main() 86 { 87 //freopen("semi.in","r",stdin); 88 scanf("%d %d %d",&n,&m,&ms); 89 int x,y; 90 for (int i=1;i<=m;i++) 91 scanf("%d %d",&x,&y),add(x,y); 92 for (int i=1;i<=n;i++) 93 if (!v[i]) tarjan(i); 94 memset(v,0,sizeof(v)); 95 for (int i=1;i<=n;i++) 96 if (!v[i]) dfs(i); 97 find(); 98 int ans=0,fig=0; 99 for (int i=1;i<=num;i++) 100 { 101 if (f[i]>ans) ans=f[i],fig=g[i]; 102 else 103 if (f[i]==ans) fig=(fig+g[i])%ms; 104 } 105 printf("%d\n",ans); 106 printf("%d\n",fig); 107 return 0; 108 }
AC without art, no better than WA !