NOIP2017模拟 轰炸 强连通分量
2017-11-04 15:33
411 查看
NOIP2017模拟 轰炸
题目大意给你n个点m条边的有向图,一次可以炸毁任意多个点(炸毁后不影响边),但前提是可到达的点不能同时炸毁,问炸毁n个点至少需要多少次?
数据范围
对于 20%的数据,n,m<=10。
对于 40%的数据,n,m<=1000。
对于另外 30%的数据,保证无环。
对于 100%的数据,n,m<=1000000
数据范围很大,这其实是一个很好的提示,似乎只能承受O(n)级别的算法。
主要说说比赛时我的思路。
“对于另外 30%的数据,保证无环”,有环或许更难考虑(通常地说都是这样),所以我们先考虑无环的情况。
在没有环的情况中,最简单的应该算一条链了。显然,要删完一条链的点必须一个一个地删。
再考虑类似树的情况,即一个节点分出多条链。
可以看出,对于分叉点A,它和它的“子树”中的点不能和A的“父亲”及以上的点同时删,但是各个“子树”中的删点是互不影响的,也就是说,可以同时进行。因此处理完A及A的“子树”的最少花费是(1+MaxLen),也就是最长链长度,这里就已经接近正解了。
所以,如果没有环,我们可以建立一个虚拟点,向原图中入度为零的点各连一条权值为0的边,那么答案就是新图中最长链的长度。
再考虑有环的情况。容易想到强连通分量缩点,Tarjan的时间复杂度O(V+E),也恰好对得上,那就考虑处在同一个强连通分量的点。由于可以互相到达,所以必须一个一个地删完。将这个强连通分量缩成一个权值等同于其中点数的新点即可。
Tarjan时间复杂度和找最长链搜索时间复杂度都是线性级别的,这样就可以AC了。
代码:
#include<stdio.h> #include<stack> #include<algorithm> #include<cstring> #define Min(x,y) ((x<y)?(x):(y)) #define MAXN 1200005 #define MAXM 1200005 using namespace std; int N,M,Ans; int en[MAXM],las[MAXN],nex[MAXM],tot; void Add(int x,int y) { en[++tot]=y; nex[tot]=las[x]; las[x]=tot; } stack<int>S; int dfn[MAXN],low[MAXN],be[MAXN],scc,VT,Size[MAXN]; bool In[MAXN]; void Tarjan(int x) { dfn[x]=low[x]=++VT; S.push(x);In[x]=true; int i,y; for(i=las[x];i;i=nex[i]) { y=en[i]; if(!dfn[y]) { Tarjan(y); low[x]=Min(low[x],low[y]); } else if(In[y])low[x]=Min(dfn[y],low[x]); } if(low[x]!=dfn[x])return; scc++; do { y=S.top();S.pop();In[y]=false; be[y]=scc;Size[scc]++; }while(y!=x); } int En[MAXM],Las[MAXN],Nex[MAXM],Tot; void ReAdd(int x,int y) { En[++Tot]=y; Nex[Tot]=Las[x]; Las[x]=Tot; } int deg[MAXN]; int f[MAXN]; int GetAns(int x)//找最长链 { if(~f[x])return f[x]; int ans=0; int i,y; for(i=Las[x];i;i=Nex[i]) { y=En[i]; ans=max(ans,GetAns(y)); } ans+=Size[x]; return f[x]=ans; } int main() { int i,j,x,y,tmp,op=0; scanf("%d%d",&N,&M); for(i=1;i<=M;i++) { scanf("%d%d",&x,&y); Add(x,y); } for(i=1;i<=N;i++)if(!dfn[i])Tarjan(i); for(x=1;x<=N;x++) { for(i=las[x];i;i=nex[i]) { y=en[i]; if(be[x]!=be[y]) { deg[be[y]]++; ReAdd(be[x],be[y]); } } } for(i=1;i<=scc;i++)if(deg[i]==0)ReAdd(scc+1,i); memset(f,-1,sizeof(f)); Ans=GetAns(scc+1); printf("%d",Ans); }
相关文章推荐
- JZOJ 5354. 【NOIP2017提高A组模拟9.9】导弹拦截
- [NOIP2017模拟]Math
- JZOJ 5197. 【NOIP2017提高组模拟7.3】C
- JZOJ5452. 【NOIP2017提高A组冲刺11.5】轰炸
- 【jzoj5358】【NOIP2017提高A组模拟9.12】【BBQ】
- JZOJ5379. 【NOIP2017提高A组模拟9.21】Victor爱数字
- JZOJ 5384. 【NOIP2017提高A组模拟9.23】四维世界
- NOIP2017 赛前模拟 7.24
- JZOJ 4921. 【NOIP2017提高组模拟12.10】幻魔皇
- NOIP2017 赛前模拟(2017.10.6)
- 【JZOJ 4931】【NOIP2017提高组模拟12.24】A
- JZOJ 5396. 【NOIP2017提高A组模拟10.6】Blocks
- JZOJ 5307. 【NOIP2017提高A组模拟8.18】偷窃 (Standard IO)
- JZOJ 5328. 【NOIP2017提高A组模拟8.22】世界线
- 【JZOJ5330】【NOIP2017提高A组模拟8.22】密码【51nod1569】二项式系数的个数
- 【JZOJ 5405】【NOIP2017提高A组模拟10.10】Permutation
- [NOIP2017模拟]拆墙
- [NOIP2017模拟]操作
- [NOIP2017模拟]疯狂的01串
- 【JZOJ5342】【NOIP2017模拟9.2A组】赤壁情