传送门: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. JavaScript--淘宝图片切换

    css样式有点问题,但是主要是js逻辑: <!DOCTYPE html> <html> <head> <meta charset="utf-8&qu ...

  2. laravel 操作日志;

    在网上寻找了许多方法,觉得有的地方看不懂,  决定自己写一些关于laravel中调用本身中的操作日志: Laravel 日志工具在强大的 Monolog 函数库上提供一层简单的功能.Laravel 默 ...

  3. jsp内建对象的作用域

  4. Nuxt.js打造旅游网站第3篇_登录页面的编写

    主要知识点: 1.使用vuex/store管理数据 2.登录注册逻辑 3.Nuxt的本地存储 1.登录页面 1.1登录页面布局 替换pages/user/login.vue的代码如下 <temp ...

  5. 2017 ACM-ICPC 亚洲区(乌鲁木齐赛区)网络赛 H Skiing【拓扑排序,关键路径】

    2017 ACM-ICPC 亚洲区(乌鲁木齐赛区)网络赛  H Skiing In this winter holiday, Bob has a plan for skiing at the moun ...

  6. XAML 很少人知道的科技 - walterlv

    原文:XAML 很少人知道的科技 - walterlv XAML 很少人知道的科技 发布于 2019-04-30 02:30 更新于 2019-04-30 11:08 本文介绍不那么常见的 XAML ...

  7. codeblocs的安装使用

    安装后,上面菜单栏 点击“Setting --> Compiler” "Creat a new project"

  8. Docker 学习笔记 2019-05-27

    Docker 学习笔记 2019-05-27 可以很方便的打包应用. 使用 docker-compose 更方便. 每个发行版安装方式不一样,如果 centos 直接安装很可能会安装成旧版本. Lin ...

  9. sum(),max(),avg(),RATIO_TO_REPORT()--分组统计

    select id,area, sum(1) over() as 总记录数, sum(1) over(partition by id) as 分组记录数, sum(score) over() as 总 ...

  10. 看看国外的JavaScript题目

    ---恢复内容开始--- 题目一 (function(){    return typeof arguments;})(); 答案:“object” arguments是对象,伪数组有两件事要注意这里 ...