您现在的位置是:主页 > news > 怎么做卡蜜网站/2024年新冠第三波症状分析

怎么做卡蜜网站/2024年新冠第三波症状分析

admin2025/6/19 5:10:51news

简介怎么做卡蜜网站,2024年新冠第三波症状分析,防制网站怎么做,南宁网站建设超薄网络题目 题目 参考资料 小蓝本(算法进阶) 做法 前置芝士:有向无环图的最小路径点覆盖。 我们证明有向无环图的可重复点集的最小路径点覆盖的个数就是答案。 设路径集合为pathpathpath,而藏身点集合为hidehidehide,…

怎么做卡蜜网站,2024年新冠第三波症状分析,防制网站怎么做,南宁网站建设超薄网络题目 题目 参考资料 小蓝本(算法进阶) 做法 前置芝士:有向无环图的最小路径点覆盖。 我们证明有向无环图的可重复点集的最小路径点覆盖的个数就是答案。 设路径集合为pathpathpath,而藏身点集合为hidehidehide,…

题目

题目

参考资料

小蓝本(算法进阶)

做法

前置芝士:有向无环图的最小路径点覆盖。

我们证明有向无环图的可重复点集的最小路径点覆盖的个数就是答案。

设路径集合为pathpathpath,而藏身点集合为hidehidehideG′G'GGGG传递闭包后的图,fa[x]fa[x]fa[x]xxx路径上往上一条边的点(而x′x'x是指往上不知多少边的点),son[x]son[x]son[x]类似,不过是往下一条边的。

首先,对于每一条最小路径,最多只能有一个藏身点,所以∣hide∣≤∣path∣|hide|≤|path|hidepath,那么我们只要能够构造出一种∣hide∣=∣path∣|hide|=|path|hide=path的方案即可。

我们先求出pathpathpath的具体方案,折在x∈G′x∈G'xG在拆点二分图G2′G_2'G2中对应左部点xxx和右部点x′x'x

  1. 依次考虑每一个非匹配点x0x_0x0
  2. x0x_0x0出发,不断访问x0,match[x0′],match[match[x0′]′]...x_0,match[x_0'],match[match[x_0']']...x0,match[x0],match[match[x0]]...,知道到达一个左部点y0y_0y0,满足它对应的右部点y0′y_0'y0是非匹配点。
  3. G′G'G中,节点x0,y0x_0,y_0x0,y0以及刚才经过的点构成一条路径,y0y_0y0是起点,x0x_0x0是终点。

上面给出的所有路径就是覆盖G′G'G中所有点的一个方案,且路径互不相交。(所以终点也不相同)

现在给出pathpathpath的每条路径上选出一个藏身点的方法:

  1. 选出pathpathpath中每条路径的终点x0x_0x0,构成集合EEE
  2. 求出从EEE中节点出发,走一条边,到达的节点结合next(E)next(E)next(E)
  3. 根据传递闭包的性质,GGG中任意两个藏身点没有路径相连,等价于G′G'G中任意两个藏身点都没有边相连,因此,若E∩next(E)=ØE∩next(E)=ØEnext(E)=Ø,则hide=Ehide=Ehide=E即为所求。
  4. 否则,考虑E∩next(E)E∩next(E)Enext(E)中每个节点eee,沿着 eee所在的路径往上走,直到一个节点e′∉next(E)e'∉next(E)e/next(E)。从EEE中删掉eee,加入e′e'e
  5. 对于修改后的集合EEE,重复执行步骤343~43 4,直至333中的条件满足。

那么现在需要证明第444步中,一定能找到合法的点e′e'e

证明几个定理:

  1. E∩next(E)E∩next(E)Enext(E)中两个点x,yx,yx,y,先跳xxx,删除xxx并加入x′x'x,一定有y∈E′∩next(E′)y∈E'∩next(E')yEnext(E),不难证明xxx能到达yyyx′x'x也能到达yyy,所以跳点的先后顺序并不会影响其中一个点少跳
  2. 对于E∩next(E)E∩next(E)Enext(E)中两个点x,yx,yx,y,如果xxx先跳会跳到x′x'xyyy先跳会跳到y′y'y,而yyyxxx跳完之后跳会跳到y′′y''y,这样说明xxx跳完后会导致yyy的多跳,但是因为如果yyy先跳,xxx后跳,这样因为x′x'x能指向y′′y''y也能指向y′y'y,所以yyy还是会跳到y′′y''y,所以跳的最终结果并不会变,只会改变跳的步骤次数(简单来说就是因为每个点不会少跳,所以最终都会跳,所以影响只分先后,不分是否)。
  3. 上面两点说明这样构造的最终方案是唯一的,且跳的步骤先后没有影响,所以可以构造出一种跳点顺序TTT和影响方案(xxx能影响yyy当且仅当因为xxx能到达yyy,导致了yyy往上跳,定义为x>>yx>>yx>>y,但是不代表xxx能到达yyy就一定是x>>yx>>yx>>y,即最多一个点能影响yyy,同时不难看出如果x>>yx>>yx>>y必然存在x−>yx->yx>y),不存在ti>>tj(i>j)t_i>>t_j(i>j)ti>>tj(i>j)

好,那么对于一个点eee,所在路劲pepepe,如果eee跳到了起点都不符合要求,就说明可以这条路径可以被瓜分殆尽,是的∣path∣−1|path|-1path1,但是这和pathpathpath最小性矛盾。

但是为什么可以被瓜分呢?这里给出一种瓜分方案的构造方法。

pepepe的路径为a0−>a1−>a2...−>aka_0->a_1->a_2...->a_ka0>a1>a2...>ak

那么存在x0−>a0x_0->a_0x0>a0,那么是不是意味着x0x_0x0的路径可以直接吞掉pepepe呢?错!x0x_0x0路径上的下一个点x1x_1x1说不定也被人指了。所以我们需要根据跳的步骤,构造一个影响方案,根据影响方案来吞掉pepepe

根据我们跳的步骤构造影响方案:
在这里插入图片描述
这样就表示x>>yx>>yx>>y(如果存在多个xxx,随便选一个),但是由于son[x]son[x]son[x]跳的时候yyy还没有跳,所以这样构造出来的方案不可能存在y′>>son[x]y'>>son[x]y>>son[x]的情况。

注:下面瓜分xxx指的是将xxx以及xxx路径上xxx所能到达的点归到其他路径中去。

好,那么对于x0x_0x0,他是某条路径的终点,有一个点yyyx0>>son[y]x_0>>son[y]x0>>son[y],那么将x0x_0x0所在的路径延长,代替son[y]son[y]son[y]以及其下面的一段,然后将yyy变为终点,且路径数不变,那么对于a0a_0a0而言,对于x0>>a0x_0>>a_0x0>>a0,只需要在此之前先把son[x0]son[x_0]son[x0]瓜分了,然后让x0x_0x0连向pepepe即可。

按照上面的瓜分方法(即如果目前瓜分的是xxx,如果存在y>>xy>>xy>>x,则先瓜分son[y]son[y]son[y],然后让yyy吞了xxx),不难证明xxx(跳点顺序中随便一个点)在不影响路径条数的情况下一定可以被瓜分,因为这样按照这样无限递增下去,接下来瓜分的点绝对不可能是xxx或者x′x'x,因为这样存在x′>>zx'>>zx>>z,但是由于递归下去的条件是存在y>>son[x]y>>son[x]y>>son[x],即跳点顺序中yyy是在xxx前面的,所以后面瓜分递归中的点在跳点顺序中是不断往前跑的,而x′>>zx'>>zx>>z很明显违背了不存在ti>>tj(i>j)t_i>>t_j(i>j)ti>>tj(i>j)这条性质,所以瓜分递归中一定最后会跳掉一条路径的ededed并停止递归,开始回溯。(当然,这里说的不影响路径条数仅当xxx不是路径起点的时候才不影响,否则条数会减一)

例子:
在这里插入图片描述

所以这样瓜分了x0x_0x0,就可以少一条路径啦。

得证。

代码

#include<cstdio>
#include<cstring>
#define  N  210
#define  M  41000
using  namespace  std;
struct  node
{int  y,next;
}a[M];int  len,last[N];
inline  void  ins(int  x,int  y){len++;a[len].y=y;a[len].next=last[x];last[x]=len;}
int  dis[N][N],n,m;
int  match[N];bool  v[N];
bool  check(int  x)
{v[x]=1;for(int  k=last[x];k;k=a[k].next){int  y=a[k].y;if(!match[y]  ||  (!v[match[y]]  &&  check(match[y])==1)){match[y]=x;return  1;}}return  0;
}
int  main()
{scanf("%d%d",&n,&m);for(int  i=1;i<=m;i++){int  x,y;scanf("%d%d",&x,&y);dis[x][y]=1;}for(int  i=1;i<=n;i++){for(int  j=1;j<=n;j++){for(int  k=1;k<=n;k++)if(dis[j][i]  &&  dis[i][k])dis[j][k]=1;}}for(int  i=1;i<=n;i++){for(int  j=1;j<=n;j++)if(dis[i][j])ins(i,j);}//传递闭包int  ans=0;for(int  i=1;i<=n;i++){memset(v,0,sizeof(v));ans+=check(i);}printf("%d\n",n-ans);return  0;
}

最后说

>>>>>>这个符号真正的意思其实是远大于的意思,但是这里为了方便重定义了这个符号,希望读者不要误解。