拓扑图就是有向无环图
拓扑排序步骤:
1.入度为0的点入队
2.用这个点更新所有连接的点,让他们的入度减1,假如入度减为0了,就入队
队列存的就是拓扑序
目录
信息学奥赛一本通(C++版)在线评测系统 (ssoier.cn)
裸的拓扑排序
- #include
- using namespace std;
- const int N=110,M=N*N/2;
- int h[N],e[M],ne[M],idx;
- int d[N],q[N];
- int n;
- void add(int a,int b)
- {
- e[idx]=b,ne[idx]=h[a],h[a]=idx++;
- }
- void topsort()
- {
- int hh=0,tt=-1;
- for(int i=1;i<=n;i++)
- if(!d[i])//把所有入度为0的点入队
- q[++tt]=i;
- while(hh<=tt)
- {
- int t=q[hh++];
- for(int i=h[t];~i;i=ne[i])//枚举子节点
- {
- int j=e[i];
- if(--d[j]==0)//入度--,假如等于0的话就入队
- q[++tt]=j;
- }
- }
- }
- int main()
- {
- memset(h,-1,sizeof h);
- cin>>n;
- for(int i=1;i<=n;i++)
- {
- int son;
- while(cin>>son,son) add(i,son),d[son]++;//son的入度+1
- }
- topsort();//做一遍拓扑排序
- for(int i=0;i
' ';//输出拓扑序 - return 0;
- }
信息学奥赛一本通(C++版)在线评测系统 (ssoier.cn)
也可以用差分约束来做,但是时间复杂度可能是n*m,拓扑排序时间复杂度是n+m,也可以用最大连通块来做(离线的tarjan)
a比b的奖金多相当于a>=b+1,相当于b->a边权是1
然后每个人最少都100块就初始化dist为100即可,然后按照拓扑序跑一遍最长路
- #include
- using namespace std;
- const int N=1e4+10,M=2e4+10;
- int h[N],e[M],ne[M],idx;
- int d[N],q[N];
- int n,m;
- int dist[N];
- void add(int a,int b)
- {
- e[idx]=b,ne[idx]=h[a],h[a]=idx++;
- }
- bool topsort()
- {
- int hh=0,tt=-1;
- for(int i=1;i<=n;i++)
- if(!d[i])//把所有入度为0的点入队
- q[++tt]=i;
- while(hh<=tt)
- {
- int t=q[hh++];
- for(int i=h[t];~i;i=ne[i])//枚举子节点
- {
- int j=e[i];
- if(--d[j]==0)//入度--,假如等于0的话就入队
- q[++tt]=j;
- }
- }
- return tt==n-1;//看看有没有环
- }
- int main()
- {
- memset(h,-1,sizeof h);
- cin>>n>>m;
- while(m--)
- {
- int a,b;
- cin>>a>>b;
- add(b,a);//b->a连条长度是1的边
- d[a]++;//a的入度+1
- }
- if(topsort())//做一遍拓扑排序,假如无环
- {
- for(int i=1;i<=n;i++) dist[i]=100;//初始化每个人都有100元
- for(int k=0;k
//枚举拓扑序列 - {
- int u=q[k];
- for(int i=h[u];~i;i=ne[i])//枚举子节点
- {
- int j=e[i];
- dist[j]=max(dist[j],dist[u]+1);//更新最长路
- }
- }
- int res=0;
- for(int i=1;i<=n;i++) res+=dist[i];//求一遍答案
- cout<
- }
- else puts("Poor Xed");//假如有环
- return 0;
- }
3.可达性统计(拓扑排序+dp)
先做一遍拓扑排序,然后将拓扑序逆序进行dp
- #include
- using namespace std;
- const int N=3e4+10,M=3e4+10;
- int h[N],e[M],ne[M],idx;
- int n,m;
- int d[N],q[N];
- bitset
f[N];//用来存储二进制的数 - void add(int a,int b)
- {
- e[idx]=b,ne[idx]=h[a],h[a]=idx++;
- }
- void topsort()//拓扑排序
- {
- int hh=0,tt=-1;
- for(int i=1;i<=n;i++)
- if(!d[i])
- q[++tt]=i;
- while(hh<=tt)
- {
- int t=q[hh++];
- for(int i=h[t];~i;i=ne[i])
- {
- int j=e[i];
- if(--d[j]==0)
- q[++tt]=j;
- }
- }
- }
- int main()
- {
- memset(h,-1,sizeof h);
- cin>>n>>m;
- while(m--)
- {
- int a,b;
- cin>>a>>b;
- add(a,b);
- d[b]++;
- }
- topsort();//跑一遍拓扑排序
- for(int i=n-1;i>=0;i--)//逆序做dp
- {
- int j=q[i];
- f[j][j]=1;//自己能到自己,所有这个位置为1
- for(int k=h[j];~k;k=ne[k])//枚举所有能到的点,进制位运算
- f[j]|=f[e[k]];
- }
- for(int i=1;i<=n;i++) cout<
count()<//输出1的个数,也即能到的点的个数 - return 0;
- }
4.车站分级(拓扑排序+最长路)
分析一下,当前车次停靠站的级别肯定是大于未停靠的级别,相当于停靠的级别>=未停靠+1,建a>=b+1的边,做一遍拓扑排序,跑最长路即可
假如直接建边就大概建很多条边,容易超内存,所有每个车次都建个虚拟中间点为n+i,则建n+i>=a,b>=n+i+1就行
因为所有车站至少为1,则dist初始化为1
然后求一遍最大级别dist即可
- #include
- using namespace std;
- const int N=2010,M=1000010;
- int h[N],e[M],ne[M],w[M],idx;
- int n,m;
- int d[N],q[N];
- int dist[N];
- bool st[N];
- void add(int a,int b,int c)
- {
- e[idx]=b,w[idx]=c,ne[idx]=h[a],h[a]=idx++;
- d[b]++;
- }
- void topsort()
- {
- int hh=0,tt=-1;
- for(int i=1;i<=n+m;i++)//因为增加了虚拟中间点
- if(!d[i])
- q[++tt]=i;
- while(hh<=tt)
- {
- int t=q[hh++];
- for(int i=h[t];~i;i=ne[i])
- {
- int j=e[i];
- if(--d[j]==0)
- q[++tt]=j;
- }
- }
- }
- int main()
- {
- memset(h,-1,sizeof h);
- cin>>n>>m;
- for(int i=1;i<=m;i++)
- {
- memset(st,0,sizeof st);//清空上一层的车站
- int cnt;
- cin>>cnt;
- int start=n,end=1;//获取开始车站与结尾车站
- while(cnt--)
- {
- int stop;
- cin>>stop;
- start=min(start,stop);
- end=max(end,stop);
- st[stop]=true;//标记这个是车站
- }
- int ver=n+i;//虚拟中间点
- for(int k=start;k<=end;k++)//枚举经过的所有车站
- if(st[k]) add(ver,k,1);//假如是车站,则ver->k条1的边
- else add(k,ver,0);//反之连k->ver条0的边
-
- }
- topsort();//跑一遍拓扑排序
- for(int i=1;i<=n;i++) dist[i]=1;//初始化为最少为1
- for(int i=0;i
//取出拓扑序 - {
- int j=q[i];
- for(int k=h[j];~k;k=ne[k])//枚举子节点
- dist[e[k]]=max(dist[e[k]],dist[j]+w[k]);//更新最长路
- }
- int res=0;
- for(int i=1;i<=n;i++) res=max(res,dist[i]);//更新最大值
- cout<
- return 0;
- }
-
相关阅读:
发明专利和实用新型专利的区别
算法模型总结:哈希
理德外汇名人故事:全球第一理财师——苏茜·欧曼
OPNET Modeler 软件的简单介绍与使用
Java面向对象(高级)-- 单例(Singleton)设计模式
ubuntu python serial实现串口数据收发
C++ 基础与深度分析 Chapter9 序列与关联容器(关联容器、适配器与生成器)
写Python爬虫又被屏蔽了,你现在需要一个稳定的代理IP
C语言牛客网(NowCoder)刷题篇
MySQL事务隔离级别详解
-
原文地址:https://blog.csdn.net/m0_63729880/article/details/126560500