区队A 拓扑图
有向无环图
定义
当一张有向图当中没有环的时候即为有向无环图(Directed Acyclic Graph,DAG)
拓扑排序
定义
在一张DAG上的一个序列
规则
- 将入度为0的节点加入队列
- 每一次都将这个节点的边删除,然后将相邻节点的入度更新减一
复杂度
\[O(n+m)
\]
不成topo_sort的情况
- 当队列当中的元素大于1,即无法确定先后顺序
- 当走完全部节点后,走的节点数小于总节点数
P1347 [ECNA 2001] 排序
思路
-
可以先建图然后每次都去跑topo
-
第一种情况就是在加入边跑完topo后发现该序列合法的情况下输出
-
第二种情我们可以发现一个性质:当我们在加入x个点,而且该图不成topo,即队列元素中有同时大于1的情况,无论后面怎么去加边,topo依旧不成立,所以我们只需要判断一下就可以了
-
第三种只需判断在所有循环结束后都没有出现上述两种情况就可以了
Code
#include<bits/stdc++.h>
using namespace std;
int n;
vector<int> e[27];
int ind[27],ind_backup[27],que[27],ans[27];
int topo()
{
copy(ind_backup+1,ind_backup+ n + 1, ind + 1);
int front = 1,tail = 0;
for(int i= 1;i<=n;i++)
{
if(ind[i] == 0)
{
que[++tail] = i;
}
}int cnt = 0;
bool flag = 0;
while(front <= tail)
{
if(tail - front + 1 > 1)
{
flag = 1;
}
int u= que[front++];
ans[++cnt] = u;
for(int i = 0 ; i < e[u].size() ; i ++)
{
int v = e[u][i];
--ind[v];
if(ind[v] == 0)
{
que[++tail] =v;
}
}
}if(cnt < n)
{
return -1;
}
if(flag)
{
return 1;
}return 0;
}
signed main()
{
ios::sync_with_stdio(0);cin.tie(0);
int m;
cin>>n>>m;
for(int i = 1;i <=m;i ++)
{
string s;
cin>>s;
int u = s[0] - 'A' + 1, v = s[2] - 'A' + 1;
e[u].push_back(v);
++ind_backup[v];
int ret = topo();
if(ret == -1)
{
cout<<"Inconsistency found after " << i << " relations.";
return 0;
}
if(ret == 0)
{
cout<<"Sorted sequence determined after "<<i<<" relations:";
for(int j = 1;j <= n;j ++)
{
cout<<(char)(ans[j] + 'A' - 1);
}
cout<<".\n";
return 0;
}
}cout<<"Sorted sequence cannot be determined.";
return 0;
}
P1807 最长路
思路
- 首先读题,其实就是在求一个最短路反过来,而且需要处理负权边topo求解
Code
#include<bits/stdc++.h>
using namespace std;
#define pii pair<int,int>
int n;
vector<pii> e[1501];
int ind[1501],que[1501],dis[1501];
signed main()
{
ios::sync_with_stdio(0);cin.tie(0);
int m;
cin>>n>>m;
for(int i = 1;i <=m;i ++)
{
int u,v,w;
cin>>u>>v>>w;
e[u].push_back({v,w});
++ind[v];
}int front = 1,tail = 0;
for(int i =2;i<=n;i++)
{
if(ind[i] == 0)
{
que[++tail] = i;
}
}
while(front<=tail)
{
int u = que[front++];
for(int i= 0 ;i < e[u].size(); i++)
{
int v = e[u][i].first;
--ind[v];
if(ind[v] == 0)
{
que[++tail] = v;
}
}
}
memset(dis,0x80,sizeof(dis));
dis[1] = 0;
que[++tail] = 1;
while(front <= tail)
{
int u = que[front++];
for(int i = 0 ; i < e[u].size(); i ++)
{
int v = e[u][i].first, w =e[u][i].second;
--ind[v];
dis[v] = max(dis[v], dis[u] + w);
if(ind[v] == 0)
{
que[++tail] = v;
}
}
}
cout<<(dis[n] == 0x80808080 ? -1 : dis[n]) << '\n';
return 0;
}
P3183 [HAOI2016] 食物链
思路
略
Code
#include<bits/stdc++.h>
using namespace std;
const int N = 1e5+10;
int n;
vector<int> e[N];
int ind[N],que[N],cnt[N];
bool flag[N];
signed main()
{
ios::sync_with_stdio(0);cin.tie(0);
int m;
cin>>n>>m;
memset(flag,true,sizeof(flag));
for(int i = 1;i <=m;i ++)
{
int u,v;
cin>>u>>v;
e[u].push_back(v);
++ind[v];
flag[u] = 0;
}int front = 1,tail = 0;
memset(cnt,0,sizeof(cnt));
for(int i = 1;i<=n;i++)
{
if(!ind[i])
{
que[++tail] = i;
flag[i] = 0;
cnt[i] = 1;
}
}
while(front <= tail)
{
int u = que[front++];
for(int i = 0 ; i < e[u].size(); i ++)
{
int v = e[u][i];
--ind[v];
cnt[v] += cnt[u];
if(ind[v] == 0)
{
que[++tail] = v;
}
}
}
int sum = 0 ;
for(int i= 1;i<=n;i++)
{
if(flag[i])
{
sum += cnt[i];
}
}cout<<sum;
return 0;
}
P1137 旅行计划v
思路
- 用dp的思想
Code
#include<bits/stdc++.h>
using namespace std;
const int N = 1e5+10;
int n;
vector<int> e[N];
int ind[N],que[N],ans[N];
//bool flag[N];
signed main()
{
ios::sync_with_stdio(0);cin.tie(0);
int m;
cin>>n>>m;
for(int i = 1;i <=m;i ++)
{
int u,v;
cin>>u>>v;
e[u].push_back(v);
++ind[v];
}int front = 1,tail = 0;
memset(ans,0,sizeof(ans));
for(int i = 1;i<=n;i++)
{
if(ind[i] == 0)
{
que[++tail] = i;
ans[i] = 1;
}
}
while(front <= tail)
{
int u = que[front++];
for(int i = 0 ; i < e[u].size(); i ++)
{
int v = e[u][i];
--ind[v];
ans[v] = max(ans[v],ans[u] + 1);
if(ind[v] == 0)
{
que[++tail] = v;
}
}
}
for(int i = 1;i<=n;i++)
{
cout<<ans[i]<<'\n';
}
return 0;
}

浙公网安备 33010602011771号