有向无环图特点:(1)每个状态没有后效性
1.有向图的拓扑序列
题目链接
#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
const int N = 100010;
int e[N],ne[N],h[N],idx=0;
int q[N];
int n,m;
int d[N]={0};
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])
{
q[++tt]=i;
}
}
while(hh<=tt)
{
int t=q[hh++];
for(int i=h[t];i!=-1;i=ne[i])
{
int j=e[i];
if(--d[j]==0)
{
q[++tt]=j;
}
}
}
return tt==n-1;
}
int main()
{
memset(h,-1,sizeof h);
cin>>n>>m;
int a,b;
while (m -- ){
cin>>a>>b;
add(a,b);
d[b]++;
}
if(!topsort())cout<<-1<<endl;
else
{
for(int i=0;i<n;i++)
cout<<q[i]<<" ";
}
}
2.可达性统计
题目链接
算法:bitset+拓扑排序
#include <iostream>
#include <cstring>
#include <algorithm>
#include <bitset>
using namespace std;
const int N = 30010;
int h[N],e[N],ne[N],idx=0;
int q[N];
bitset<N>f[N];
int n,m;
int d[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!=-1;i=ne[i])
{
int j=e[i];
if(--d[j]==0)
{
q[++tt]=j;
}
}
}
}
int main()
{
cin>>n>>m;
memset(h,-1,sizeof h);
int a,b;
while (m -- ){
cin>>a>>b;
add(a,b);
d[b]++;
}
topsort();
for(int i=n-1;i>=0;i--)
{
int t=q[i];
f[t][t]=1;
for(int k=h[t];k!=-1;k=ne[k])
{
f[t]|=f[e[k]];
}
}
for(int i=1;i<=n;i++)cout<<f[i].count()<<endl;
}
3.奖金
题目链接
虚拟原点建立但省略了,边的权值为正,用拓扑更简单,若为负,此题需用差分约束来写
#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
const int N = 10010,M=20010;
int h[N],e[M],ne[M],idx=0;
int q[N];
int st[N];
int d[N];
int dist[N];
int n,m;
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!=-1;i=ne[i])
{
int j=e[i];
if(--d[j]==0)
{
q[++tt]=j;
}
}
}
return tt==n-1;
}
int main()
{
memset(h,-1,sizeof h);
cin>>n>>m;
int a,b;
while (m -- ){
cin>>a>>b;
add(b,a);
d[a]++;
}
if(!topsort())
{
cout<<"Poor Xed"<<endl;
return 0;
}
for(int i=1;i<=n;i++)dist[i]=100;
for(int k=0;k<n;k++)
{
int t=q[k];
for(int i=h[t];i!=-1;i=ne[i])
{
int j=e[i];
dist[j]=max(dist[j],dist[t]+1);
}
}
int res=0;
for(int i=1;i<=n;i++)res+=dist[i];
cout<<res<<endl;
}
4.车站分级
题目链接
难点:建立虚拟原点否则会爆空间。
这道题很难想象用拓扑排序来做,属于一道难题
#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
const int N = 2010,M=1000010;
int n,m;
int h[N],ne[M],e[M],w[M],idx=0;
int q[N],d[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]++;
}
bool topsort()
{
int hh=0,tt=-1;
for(int i=1;i<=n+m;i++)
{
if(d[i]==0)
{
q[++tt]=i;
}
}
while(hh<=tt)
{
int t=q[hh++];
for(int i=h[t];i!=-1;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,x;
cin>>cnt;
int start=n,end=1;
while(cnt--)
{
cin>>x;
start=min(start,x);
end=max(end,x);
st[x]=true;
}
int ver=n+i;
for(int j=start;j<=end;j++)
{
if(!st[j])add(j,ver,0);
else add(ver,j,1);
}
}
topsort();
for(int i=1;i<=n;i++)dist[i]=1;
for(int k=0;k<n+m;k++)
{
int t=q[k];
for(int i=h[t];i!=-1;i=ne[i])
{
int j=e[i];
dist[j]=max(dist[j],dist[t]+w[i]);
}
}
int res=0;
for(int i=1;i<=n;i++)
{
res=max(res,dist[i]);
}
cout<<res<<endl;
}
5.家谱树
题目链接
#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
const int N = 110,M=N*N;
int h[N],e[M],ne[M],idx=0;
int q[N],d[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!=-1;i=ne[i])
{
int j=e[i];
if(--d[j]==0)
{
q[++tt]=j;
}
}
}
}
int main()
{
cin>>n;
int x;
memset(h,-1,sizeof h);
for(int i=1;i<=n;i++)
{
while(cin>>x,x)
{
add(i,x);
d[x]++;
}
}
topsort();
for(int i=0;i<n;i++)cout<<q[i]<<" ";
}