欢迎访问 生活随笔!

生活随笔

当前位置: 首页 > 编程资源 > 编程问答 >内容正文

编程问答

P7516-[省选联考2021A/B卷]图函数【bfs】

发布时间:2023/12/3 编程问答 38 豆豆
生活随笔 收集整理的这篇文章主要介绍了 P7516-[省选联考2021A/B卷]图函数【bfs】 小编觉得挺不错的,现在分享给大家,帮大家做个参考.

正题

题目链接:https://www.luogu.com.cn/problem/P7516


题目大意

懒了,直接抄题意了
对于一张 nnn 个点 mmm 条边的有向图 GGG(顶点从 1∼n1 \sim n1n 编号),定义函数 f(u,G)f(u, G)f(u,G)

  • 初始化返回值 cnt=0cnt = 0cnt=0,图 G′=GG'= GG=G
  • 111nnn 按顺序枚举顶点 vvv,如果当前的图 G′;G';G; 中,从 uuuvvv 与从 vvvuuu 的路径都存在,则将 cnt+1cnt + 1cnt+1,并在图 G′;G';G; 中删去顶点 vvv 以及与它相关的边。
  • 222 步结束后,返回值 cntcntcnt 即为函数值。
  • 现在给定一张有向图 GGG,请你求出 h(G)=f(1,G)+f(2,G)+⋯+f(n,G)h(G) = f(1, G) + f(2, G) + \cdots + f(n, G)h(G)=f(1,G)+f(2,G)++f(n,G) 的值。

    更进一步地,记删除(按输入顺序给出的)第 111iii 条边后的图为 GiG_iGi1≤i≤m1 \le i \le m1im),请你求出所有 h(Gi)h(G_i)h(Gi) 的值。

    1≤n≤103,1≤m≤2×1051\leq n\leq 10^3,1\leq m\leq 2\times 10^51n103,1m2×105


    解题思路

    但凡一个不按惯性思维思考的方法都可以做出这道题

    这个删边就很意义不明,反过来直接改成加边就简单很多。

    然后还有一个问题就是是否删点的判断也是没有必要的:

    假设对于起点uuu能走到vvvvvv不能走到uuu,那么显然并不存在一个节点xxx使得uuu能走到xxxxxx能走到uuu并且vvv是这些路径的必经点,因为那么vvv肯定在这个环上,那么vvv显然能走到uuu

    所以现在f(u,G)f(u,G)f(u,G)能否统计vvv就变为了判断是否存在一个u→v→uu\rightarrow v\rightarrow uuvu的环使得路径上的所有点编号不小于min(u,v)min(u,v)min(u,v)

    那么不妨考虑一下两个点对(u,v)(u,v)(u,v)之间不断加边之后第一次产生贡献的时间,每条边的权值设为加入的时间,这个时间就是u→v→uu\rightarrow v\rightarrow uuvu的一条不经过编号小于min(u,v)min(u,v)min(u,v)点的情况下最大权值最小的路径。

    这样Flody就有O(n3)O(n^3)O(n3)的算法了。

    然后我们想了很久感觉最短路行不通,那么此时就需要摒弃惯性思维的想法了,我们考虑另一个更暴力的做法,我们每次加边然后暴力判断每个点之间的联通,发现这样的时间复杂度是O(nm2)O(nm^2)O(nm2)的。

    然后依旧的我们考虑另一种可能,我们最外层不枚举加边,而是枚举需要统计答案的起点uuu,然后每次加一条边(x,y)(x,y)(x,y),如果uuu能走到xxx且不能走到yyy那么此时uuu能走到yyy了,从yyy开始bfsbfsbfs所有其他没有走过的节点,需要注意的是走过的边两边都是遍历过的所以可以直接删除。

    这样的时间复杂度就是O(n(n+m))O(n(n+m))O(n(n+m)),可以通过本题。

    需要卡常


    code

    #include<cstdio> #include<cstring> #include<algorithm> #include<vector> #include<queue> using namespace std; const int N=1e3+10,M=2e5+10; struct node{int to,next; }a[M]; int n,m,f[N][N],g[N][N]; int ex[M],ey[M],ans[M]; vector<int> G[N],D[N];queue<int> q; void bfs(int x,int s,int w){q.push(x);while(!q.empty()){int x=q.front();q.pop();f[s][x]=w;for(int i=0;i<G[x].size();i++)if(!f[s][G[x][i]])q.push(G[x][i]);G[x].clear();}return; } void bgs(int x,int s,int w){q.push(x);while(!q.empty()){int x=q.front();q.pop();g[s][x]=w;for(int i=0;i<D[x].size();i++)if(!g[s][D[x][i]])q.push(D[x][i]);D[x].clear();}return; } int main() {scanf("%d%d",&n,&m);m++;for(int i=2;i<=m;i++)scanf("%d%d",&ex[i],&ey[i]);reverse(ex+2,ex+1+m);reverse(ey+2,ey+1+m);for(int x=1;x<=n;x++){for(int i=1;i<=n;i++)G[i].clear();for(int i=1;i<=n;i++)D[i].clear();f[x][x]=g[x][x]=1;for(int i=2;i<=m;i++){if(ex[i]<x||ey[i]<x)continue;if(f[x][ex[i]]&&!f[x][ey[i]])bfs(ey[i],x,i);else if(!f[x][ex[i]]&&!f[x][ey[i]])G[ex[i]].push_back(ey[i]);if(g[x][ey[i]]&&!g[x][ex[i]])bgs(ex[i],x,i);else if(!g[x][ey[i]]&&!g[x][ex[i]])D[ey[i]].push_back(ex[i]);}}for(int i=1;i<=n;i++)for(int j=i;j<=n;j++)if(f[i][j]&&g[i][j])ans[max(f[i][j],g[i][j])]++;for(int i=1;i<=m;i++)ans[i]+=ans[i-1];reverse(ans+1,ans+1+m);for(int i=1;i<=m;i++)printf("%d ",ans[i]);return 0; }

    总结

    以上是生活随笔为你收集整理的P7516-[省选联考2021A/B卷]图函数【bfs】的全部内容,希望文章能够帮你解决所遇到的问题。

    如果觉得生活随笔网站内容还不错,欢迎将生活随笔推荐给好友。