[CSP校内集训]pestc(拓扑排序)
时间:2019-11-06
本文章向大家介绍[CSP校内集训]pestc(拓扑排序),主要包括[CSP校内集训]pestc(拓扑排序)使用实例、应用技巧、基本知识点总结和需要注意事项,具有一定的参考价值,需要的朋友可以参考一下。
题意
给一个边带权的有向图,可以花费边权使得一条边反向;通过翻转边让原图变成一个DAG,最小化所有花费中的最大值\(,(n,m\leq 200000)\),保证无重边和自环
解法1
考场上面没看出来性质,于是口胡了一个乱搞做法
连好边后直接对原图进行一遍拓扑排序,由于原图不是DAG,所以一定会有无法入队的环存在;如果当前队列为空而有点没有被遍历到,那么就强行选择一个点将连向它的边翻转;
具体的,我们选择\(max(\) 连向i的边 \()\)最小的\(i\),由于翻转了连向i的边,需要将\(ans\)与\(max(\) 连向i的边 \()\)取最大值
维护max值用大根堆,维护max值最小的点用set,虽说复杂度为\(O(nlogn)\)但并不好写(为什么还跑的比正解快啊qwq)
Code
#include<bits/stdc++.h>
#define N 200005
#define Min(x,y) ((x)<(y)?(x):(y))
#define Max(x,y) ((x)>(y)?(x):(y))
using namespace std;
typedef long long ll;
int n,m,rd[N],ans=0;
bool vis[N];
struct Edge
{
int next,to,dis;
}edge[N<<1];int head[N],cnt;
void add_edge(int from,int to,int dis)
{
edge[++cnt].next=head[from];
edge[cnt].to=to;
edge[cnt].dis=dis;
head[from]=cnt;
}
priority_queue<int> mx[N];//一个大根堆维护指向一个点最大的边权
priority_queue<int> lz[N];//一个大根堆懒删除
set< pair<int,int> > s;//一个set维护最大边权最小的点编号
template <class T>
void read(T &x)
{
char c; int sign=1;
while((c=getchar())>'9'||c<'0') if(c=='-') sign=-1; x=c-48;
while((c=getchar())>='0'&&c<='9') x=(x<<1)+(x<<3)+c-48; x*=sign;
}
void topo()//检验能否完成一次拓扑
{
queue<int> q;
for(int i=1;i<=n;++i)
if(!rd[i]) q.push(i);
else s.insert(make_pair(mx[i].top(),i));
int rest=n;
while(rest)
{
--rest;
int v,u;
if(q.empty())//成环了
{
v=s.begin()->first,u=s.begin()->second;
while(!s.empty()&&vis[u])
{
s.erase(make_pair(v,u));
v=s.begin()->first;u=s.begin()->second;
}
ans=Max(ans,v);
}
else {u=q.front();q.pop();}
vis[u]=1;
for(int i=head[u];i;i=edge[i].next)
{
int v=edge[i].to;
if(--rd[v]==0 && !vis[v]) {q.push(v);vis[v]=1;continue;}
//如果没有入队就更新
lz[v].push(edge[i].dis);//删除这条边
s.erase(make_pair(mx[v].top(),v));//更新最大值
while(!lz[v].empty()&&mx[v].top()==lz[v].top())
{
mx[v].pop();
lz[v].pop();
}
s.insert(make_pair(mx[v].top(),v));
}
}
}
int main()
{
freopen("pestc.in","r",stdin);
freopen("pestc.out","w",stdout);
read(n);read(m);
for(int i=1;i<=m;++i)
{
int x,y,z;
read(x);read(y);read(z);
add_edge(x,y,z);
mx[y].push(z);
++rd[y];
}
topo();
cout<<ans<<endl;
return 0;
}
解法2
原文地址:https://www.cnblogs.com/Chtholly/p/11805034.html
- JavaScript 教程
- JavaScript 编辑工具
- JavaScript 与HTML
- JavaScript 与Java
- JavaScript 数据结构
- JavaScript 基本数据类型
- JavaScript 特殊数据类型
- JavaScript 运算符
- JavaScript typeof 运算符
- JavaScript 表达式
- JavaScript 类型转换
- JavaScript 基本语法
- JavaScript 注释
- Javascript 基本处理流程
- Javascript 选择结构
- Javascript if 语句
- Javascript if 语句的嵌套
- Javascript switch 语句
- Javascript 循环结构
- Javascript 循环结构实例
- Javascript 跳转语句
- Javascript 控制语句总结
- Javascript 函数介绍
- Javascript 函数的定义
- Javascript 函数调用
- Javascript 几种特殊的函数
- JavaScript 内置函数简介
- Javascript eval() 函数
- Javascript isFinite() 函数
- Javascript isNaN() 函数
- parseInt() 与 parseFloat()
- escape() 与 unescape()
- Javascript 字符串介绍
- Javascript length属性
- javascript 字符串函数
- Javascript 日期对象简介
- Javascript 日期对象用途
- Date 对象属性和方法
- Javascript 数组是什么
- Javascript 创建数组
- Javascript 数组赋值与取值
- Javascript 数组属性和方法