codeforces gym100801 Problem G. Graph
传送门: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的更多相关文章
- codeforces gym100801 Problem J. Journey to the “The World’s Start”
传送门:https://codeforces.com/gym/100801 题意: 小明坐地铁,现在有n-1种类型的地铁卡卖,现在小明需要买一种地铁票,使得他可以在t的时间内到达终点站,地铁票的属性为 ...
- Codeforces Gym 100513G G. FacePalm Accounting
G. FacePalm Accounting Time Limit: 20 Sec Memory Limit: 256 MB 题目连接 http://codeforces.com/gym/100513 ...
- Codeforces Gym 100637G G. #TheDress 暴力
G. #TheDress Time Limit: 20 Sec Memory Limit: 256 MB 题目连接 http://codeforces.com/gym/100637/problem/G ...
- Codeforces Gym 100513G G. FacePalm Accounting 暴力
G. FacePalm Accounting Time Limit: 20 Sec Memory Limit: 256 MB 题目连接 http://codeforces.com/gym/100513 ...
- Codeforces #550 (Div3) - G.Two Merged Sequences(dp / 贪心)
Problem Codeforces #550 (Div3) - G.Two Merged Sequences Time Limit: 2000 mSec Problem Description T ...
- 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 ...
- 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 ...
- 论文解读《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:Problem G: 克隆人来了!
想要输出""的话: cout<<"A person whose name is \""<<name<<" ...
随机推荐
- 【JZOJ4889】【NOIP2016提高A组集训第14场11.12】最长公共回文子序列
题目描述 YJC最近在学习字符串的有关知识.今天,他遇到了这么一个概念:最长公共回文子序列.一个序列S,如果S是回文的且分别是两个或多个已知序列的子序列,且是所有符合此条件序列中最长的,则 S 称为已 ...
- ORA-03113: end-of-file on communication channel 解决方法
今天在测试数据库中对一个表插入了大量的数据, 导致数据库卡死 hang 住, 重启数据库后报错如下: C:\Documents and Settings\davidd>sqlplus " ...
- Introduction to 3D Game Programming with DirectX 12 学习笔记之 --- 第十六章:实例化和截头锥体裁切
原文:Introduction to 3D Game Programming with DirectX 12 学习笔记之 --- 第十六章:实例化和截头锥体裁切 代码工程地址: https://git ...
- 2018-11-3-WPF-内部的5个窗口之-MediaContextNotificationWindow
title author date CreateTime categories WPF 内部的5个窗口之 MediaContextNotificationWindow lindexi 2018-11- ...
- oralce GROUPING
/*从上面的结果中我们很容易发现,每个统计数据所对应的行都会出现null, 如何来区分到底是根据那个字段做的汇总呢,grouping函数判断是否合计列!*/ select decode(groupin ...
- Istio on ACK集成生态(2): 扩展AlertManager集成钉钉助力可观测性监控能力
阿里云容器服务Kubernetes(简称ACK)支持一键部署Istio,可以参考文档在ACK上部署使用Isito.Istio on ACK提供了丰富的监控能力,为网格中的服务收集遥测数据,其中Mixe ...
- Laravel 下的伪造跨站请求保护 CSRF#
简介# Laravel 可以轻松地保护应用程序免受跨站请求伪造(CSRF) 的攻击.跨站请求伪造是一种恶意的攻击, 他凭借已通过身份验证的用户身份来运行未经过授权的命令. Laravel 会自动为每个 ...
- HZOJ 那一天我们许下约定
比较好想的一道题,只是那个组合数比较恶心. 先说一下我最开始想的$n^4$的沙雕dp: 设f[i][j][k]为前i天给了j个,第i天给了k个,则f[i][j][k]=∑f[i-1][j-k][o]; ...
- 神经网络入门——8XOR感知器
XOR 感知器 XOR 感知器就是一个这样的逻辑门:输入相同返回 0 ,输入不同返回 1.与之前的感知器不同,这里并不是线性可分的.要处理这类较为复杂的问题,我们需要把感知器连接起来. 我们用 ...
- 割点(tarjan)
对于根来说,如果它有超过1棵子树,那么它是一个割点 对于非叶结点来说,如果它的某一个儿子没有回边能到达高于它的点,那么它是一个割点 叶节点不是割点 //洛谷3388 #include<algor ...