传送门:https://codeforces.com/gym/100801

题意:

给你一个DAG图,你最多可以进行k次操作,每次操作可以连一条有向边,问你经过连边操作后最小拓扑序的最大值是多少

题解:

最小拓扑序:与普通拓扑序不同的是,用一个小根堆记录入度为0的点做拓扑排序即可

怎么样使得最小拓扑序最大呢?已知拓扑序是入度小的点在前面,那么,如果我们可以使得大的点的度数尽量小或者是小的点度数尽量大就可以使得拓扑序变大了,由于我们只有加边的操作,那么我们可以将边尽量从大的点往小的点去连边

我们定义小根堆q以便于得到最小拓扑序

为了使得最小拓扑序最大,我们这里有一个贪心的过程

贪心的正确性证明:如果当前操作使得当前字典序最大,那么所有操作后字典序一定最大

我们把已经加边的点不直接输出。而是扔进一个大根堆里。

因为这些点之间并没有前后效应,即,我们出任意一个点都是可以的。

所以我们扔进大根堆里,当不得不出的时候,我们一定从大根堆里,选取编号最大的节点拓扑出去

所以,如果当前没有节点入度为0怎么办?很显然,从大根堆里直接拓扑。

每次取出小根堆中的点时,我们都将小根堆中的点往大根堆里面放,如果小根堆为空时,我们就需要对大根堆中的点进行连边操作了,取出大根堆中的点,进行拓扑排序的正常操作记录答案即可;

代码:

/**
*        ┏┓    ┏┓
*        ┏┛┗━━━━━━━┛┗━━━┓
*        ┃       ┃  
*        ┃   ━    ┃
*        ┃ >   < ┃
*        ┃       ┃
*        ┃... ⌒ ...  ┃
*        ┃       ┃
*        ┗━┓   ┏━┛
*          ┃   ┃ Code is far away from bug with the animal protecting          
*          ┃   ┃ 神兽保佑,代码无bug
*          ┃   ┃           
*          ┃   ┃       
*          ┃   ┃
*          ┃   ┃           
*          ┃   ┗━━━┓
*          ┃       ┣┓
*          ┃       ┏┛
*          ┗┓┓┏━┳┓┏┛
*           ┃┫┫ ┃┫┫
*           ┗┻┛ ┗┻┛
*/
// warm heart, wagging tail,and a smile just for you!
//
// _ooOoo_
// o8888888o
// 88" . "88
// (| -_- |)
// O\ = /O
// ____/`---'\____
// .' \| |// `.
// / \||| : |||// \
// / _||||| -:- |||||- \
// | | \\ - /// | |
// | \_| ''\---/'' | |
// \ .-\__ `-` ___/-. /
// ___`. .' /--.--\ `. . __
// ."" '< `.___\_<|>_/___.' >'"".
// | | : `- \`.;`\ _ /`;.`/ - ` : | |
// \ \ `-. \_ __\ /__ _/ .-` / /
// ======`-.____`-.___\_____/___.-`____.-'======
// `=---='
// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
// 佛祖保佑 永无BUG
#include <set>
#include <map>
#include <deque>
#include <queue>
#include <stack>
#include <cmath>
#include <ctime>
#include <bitset>
#include <cstdio>
#include <string>
#include <vector>
#include <cstdlib>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std; typedef long long LL;
typedef pair<LL, LL> pLL;
typedef pair<LL, int> pLi;
typedef pair<int, LL> pil;;
typedef pair<int, int> pii;
typedef unsigned long long uLL;
#define ls rt<<1
#define rs rt<<1|1
#define lson l,mid,rt<<1
#define rson mid+1,r,rt<<1|1
#define bug printf("*********\n")
#define FIN freopen("input.txt","r",stdin);
#define FON freopen("output.txt","w+",stdout);
#define IO ios::sync_with_stdio(false),cin.tie(0)
#define debug1(x) cout<<"["<<#x<<" "<<(x)<<"]\n"
#define debug2(x,y) cout<<"["<<#x<<" "<<(x)<<" "<<#y<<" "<<(y)<<"]\n"
#define debug3(x,y,z) cout<<"["<<#x<<" "<<(x)<<" "<<#y<<" "<<(y)<<" "<<#z<<" "<<z<<"]\n" const double eps = 1e-8;
const int mod = 1e9 + 7;
const int maxn = 3e5 + 5;
const int INF = 0x3f3f3f3f;
const LL INFLL = 0x3f3f3f3f3f3f3f3f;
struct EDGE {
int v, nxt;
} edge[maxn << 1];
int head[maxn], tot;
void add_edge(int u, int v) {
edge[tot].v = v;
edge[tot].nxt = head[u];
head[u] = tot++;
}
int degree[maxn];
vector<int> G[maxn];
priority_queue<int, vector<int>, greater<int> >q; //小根堆放现在的点
priority_queue<int> p;//大根堆放要连的点
int ans[maxn];
int num, used;
int a[maxn], b[maxn];
void solve(int u) {
//排序排序
ans[++num] = u;
for(int i = 0; i < G[u].size(); i++) if(!--degree[G[u][i]]) q.push(G[u][i]);
if(q.empty()) {
if(!p.empty()) {
int v = p.top(); p.pop();
//大往小连边
G[u].push_back(v);
//记录加的边
a[++used] = u; b[used] = v;
solve(v);
}
}
}
int main() {
#ifndef ONLINE_JUDGE
FIN
#endif
// freopen("graph.in", "r", stdin);
// freopen("graph.out", "w+", stdout);
int n, m, k;
scanf("%d%d%d", &n, &m, &k);
memset(head, -1, sizeof(head));
memset(degree, 0, sizeof(degree));
tot = 0;
for(int i = 1, u, v; i <= m; i++) {
scanf("%d%d", &u, &v);
add_edge(u, v);
G[u].push_back(v);
degree[v]++;
}
for(int i = 1; i <= n; i++) {
if(degree[i] == 0) q.push(i);
}
while(!q.empty()) {
//小根堆不为空或者大根堆不为空并且小根堆堆顶的元素小于大根堆堆顶的元素
if(k && (q.size() > 1 || (!p.empty() && q.top() < p.top()))) {
k--;
int u = q.top();
q.pop();
p.push(u);
//如果入度为0的点用完了,就开始连边
if(q.empty()) {
int v = p.top(); p.pop();
G[ans[num]].push_back(v);
//记录加的边
a[++used] = ans[num]; b[used] = v;
solve(v);
}
} else {
//如果当前点是最后一个入度为0的点,那么加边是没有意义的,直接拓扑
//如果当前这个点是当前最后一个入度为0的点,而且没有点是已经被加边的,那这个点如果加边,我们就是浪费了一条边,不如直接拓扑出
//如果当前这个点是当前最后一个入度为0的点,而且它比当前所有已经被加边的点的编号要大,那加边也是在浪费边,也不如直接拓扑出
int v = q.top(); q.pop();
solve(v);
}
}
for(int i = 1; i <= n; i++) {
printf("%d%c", ans[i], i == n ? '\n' : ' ');
}
printf("%d\n", used);
for(int i = 1; i <= used; i++) {
printf("%d %d\n", a[i], b[i]);
}
return 0;
}

codeforces gym100801 Problem G. Graph的更多相关文章

  1. codeforces gym100801 Problem J. Journey to the “The World’s Start”

    传送门:https://codeforces.com/gym/100801 题意: 小明坐地铁,现在有n-1种类型的地铁卡卖,现在小明需要买一种地铁票,使得他可以在t的时间内到达终点站,地铁票的属性为 ...

  2. Codeforces Gym 100513G G. FacePalm Accounting

    G. FacePalm Accounting Time Limit: 20 Sec Memory Limit: 256 MB 题目连接 http://codeforces.com/gym/100513 ...

  3. Codeforces Gym 100637G G. #TheDress 暴力

    G. #TheDress Time Limit: 20 Sec Memory Limit: 256 MB 题目连接 http://codeforces.com/gym/100637/problem/G ...

  4. Codeforces Gym 100513G G. FacePalm Accounting 暴力

    G. FacePalm Accounting Time Limit: 20 Sec Memory Limit: 256 MB 题目连接 http://codeforces.com/gym/100513 ...

  5. Codeforces #550 (Div3) - G.Two Merged Sequences(dp / 贪心)

    Problem  Codeforces #550 (Div3) - G.Two Merged Sequences Time Limit: 2000 mSec Problem Description T ...

  6. Educational Codeforces Round 40 G. Castle Defense (二分+滑动数组+greedy)

    G. Castle Defense time limit per test 1.5 seconds memory limit per test 256 megabytes input standard ...

  7. Educational Codeforces Round 37 G. List Of Integers (二分,容斥定律,数论)

    G. List Of Integers time limit per test 5 seconds memory limit per test 256 megabytes input standard ...

  8. 论文解读《Measuring and Relieving the Over-smoothing Problem for Graph NeuralNetworks from the Topological View》

    论文信息 论文标题:Measuring and Relieving the Over-smoothing Problem for Graph NeuralNetworks from the Topol ...

  9. 实验9:Problem G: 克隆人来了!

    想要输出""的话: cout<<"A person whose name is \""<<name<<" ...

随机推荐

  1. iOS学习系列 - 扩展机制category与associative

    iOS学习系列 - 扩展机制category与associative category与associative作为objective-c的扩展机制的两个特性,category即类型,可以通过它来扩展方 ...

  2. 17个你必须牢记的Win10快捷键

    电脑初学者掌握了盲打技术,可以提高录入速度:游戏玩家掌握了快捷键,可以在瞬息百变的对战中提高生存的机会:而Windows玩家掌握了快捷键,不但可以提高电脑操作速度,更能享受到初级玩家望着你那仰慕的眼神 ...

  3. assigned before calling save & JPA id生成策略

    撸了今年阿里.网易和美团的面试,我有一个重要发现.......>>> Ⅰ 关于JPA 主键,自定义生成遇到的问题,愚蠢的笔记 Ⅱ 第一次 报错: ids for this class ...

  4. I/O模型: 阻塞、非阻塞、I/O复用、同步、异步

    I/O模型不论在实际使用还是准备笔试面试中都是重要的内容,参考Unix网络编程进行总结如下.(尤其注意红色标注处) 1. 明确I/O考察的对象和流程 参考Unix网络编程,一个输入操作通常包括两个不同 ...

  5. C#中的字段,常量,属性与方法

    以前是学C++的,初次学微软的C#头都大了.什么字段,常量,属性,方法......微软把别人的东西拿来糅合在C#里,弄成了一个“大杂烩”.其实,说到底,“字段”不就是“变量”吗,所谓的“方法”不就是“ ...

  6. 开发者必知的8款App快速开发工具开发者必知的8款App快速开发工具

    "我有一个好创意,就差一个CTO……" "原生APP开发难度大,周期长,成本高,还没上线市场已经被占领了." "APP版本迭代更新,都是企业的一道难关 ...

  7. QT 建立信号和槽的联系(事件处理)

    Qt中事件处理机制叫做“信号”和“槽”signal &slot. 其模型为: 对象a中有一个信号signal:XXX(代表一个事件) 对象b中有一个槽slot:YYY(事件处理函数) 用con ...

  8. Python基础:13装饰器

    装饰器是一个很著名的设计模式,经常被用于有切面需求的场景,较为经典的应用有插入日志.性能测试.事务处理等.装饰器是解决这类问题的绝佳设计,有了装饰器,我们就可以抽离出大量函数中与函数功能本身无关的雷同 ...

  9. HZOJ 走格子

    作者的正解: 对于100%的数据:行动可以分为两种: 1. 步行,花费一个单位的时间移动到4联通的相邻格子中去. 2. 使用传送门,指定一个方向的墙的前面的一个格子,步行至最近的一个墙的面前,使用传送 ...

  10. 解决某些手机RadioGroup中的RadioButton不居中(右移)问题

    最近一直在忙一个项目,页面的基本框架类似于QQ那样,有底部导航栏的,遂采用的是RadioButton来实现的.本来一直在我的模拟器上测试,页面展示是没啥问题的,效果图如下: 可是,坑爹的事今天却发生了 ...