传送门: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. win2003开启telnet

    1.在服务器上,cmd中输入命令services.msc打开服务窗口,找到telnet服务,先开启它的依赖服务Remote Procedure Call,在开启telnet服务. 2.本地电脑中cmd ...

  2. 三、python-json、正则

    一.json   1.导入模块 import json 2.常用方法 dumps:序列化,把一个Python对象转化成json字符串 loads:反序列化,把json字符串转化成python dump ...

  3. Python学习之路12☞模块与包

    一 模块 1.1 什么是模块? 一个模块就是一个包含了python定义和声明的文件,文件名就是模块名字加上.py的后缀. 1.2 为何要使用模块? 如果你退出python解释器然后重新进入,那么你之前 ...

  4. hdu2577 dp

    也可以字符串搞.dp思路还是很清晰的.dp[][0]表示未锁定,dp[][1]表示锁定键. #include<stdio.h> #include<string.h> #defi ...

  5. 如何编写go代码

    go是一种静态编译型的语言,它的编译速度非常快. go的官方编译器称为gc,包括编译工具5g,6g和8g,连接工具5l,6l和8l.其中的数字表示处理器的架构.我们不必关心如何挑选这些工具,因为go提 ...

  6. selenium 图片上传

    WebElement  file = driver.findElement(By.name("filename")); 给此元素设置值:file.sendKeys("E: ...

  7. EF ObjectStateManager无法跟踪具有相同键的多个对象 标签: EasyUIc# 2015-09-05 11:01 1181人阅读

    最近做一个项目,因为是重构,好多代码是搬过来的,但是因为框架不同,所以搬过来也出现了很多问题,前几天在调试的时候,就碰到一个EF框架经常出现的问题:ObjectStateManager中已存在具有同一 ...

  8. IDEA使用中文api鼠标提示的设置

    最近都在用IDEA来练习,发现有的方面确实比eclipse好用,eclipse里面可添加中文的API 提示,对初期的我帮助很大,但是IDEA却没有找到添加的地方,一直以来还以为不支持这个功能,比较遗憾 ...

  9. Jmeter正则表达式提取多个值示例

    首先了解一下常用正则表达式的语法 \d           数字 \w          数字或者字母 .             可以匹配任意字符 星号*     表示任意个字符  +       ...

  10. selenium webdriver学习(八)------------如何操作select下拉框(转)

    selenium webdriver学习(八)------------如何操作select下拉框 博客分类: Selenium-webdriver   下面我们来看一下selenium webdriv ...