IOI2021集训队作业 181SG Graph
一个DAG,你可以加至多k条边,使它的字典序最小的拓扑序最大。
n≤105
维护两个集合S和T分别表示零度点和加了某条入边的点。
贪心地钦定即可。
using namespace std;
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <set>
#define N 100010
#define K 100010
int n,m,k;
struct EDGE{
int to;
EDGE *las;
} e[N];
int ne;
EDGE *last[N];
int d[N];
set<int> S,T;
int ans[N],pre[N];
void modify(int x){
for (EDGE *ei=last[x];ei;ei=ei->las)
if (!--d[ei->to])
S.insert(ei->to);
}
int main(){
freopen("in.txt","r",stdin);
scanf("%d%d%d",&n,&m,&k);
for (int i=1;i<=m;++i){
int u,v;
scanf("%d%d",&u,&v);
e[ne]={v,last[u]};
last[u]=e+ne++;
d[v]++;
}
for (int i=1;i<=n;++i)
if (d[i]==0)
S.insert(i);
for (int i=1;i<=n;++i){
if (S.empty()){
auto p=--T.end();
ans[i]=*p;
pre[*p]=ans[i-1];
modify(*p);
T.erase(p);
}
else{
while (k && S.size()>1){
auto p=S.begin();
T.insert(*p);
S.erase(*p);
--k;
}
auto p=S.begin();
if (!T.empty() && k && *--T.end()>*p){
T.insert(*p);
S.erase(p);
--k;
p=--T.end();
ans[i]=*p;
pre[*p]=ans[i-1];
modify(*p);
T.erase(p);
}
else{
ans[i]=*p;
modify(*p);
S.erase(p);
}
}
}
for (int i=1;i<=n;++i)
printf("%d ",ans[i]);
printf("\n");
int cnt=0;
for (int i=1;i<=n;++i)
if (pre[i])
++cnt;
printf("%d\n",cnt);
for (int i=1;i<=n;++i)
if (pre[i])
printf("%d %d\n",pre[i],i);
return 0;
}
分类:
贪心
, IOI2021集训队作业
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 深入理解 Mybatis 分库分表执行原理
· 如何打造一个高并发系统?
· .NET Core GC压缩(compact_phase)底层原理浅谈
· 现代计算机视觉入门之:什么是图片特征编码
· .NET 9 new features-C#13新的锁类型和语义
· Spring AI + Ollama 实现 deepseek-r1 的API服务和调用
· 《HelloGitHub》第 106 期
· 数据库服务器 SQL Server 版本升级公告
· 深入理解Mybatis分库分表执行原理
· 使用 Dify + LLM 构建精确任务处理应用