-->

贪心算法

1)题解

•        分别用V0、V1和V>=2表示度为0、1以及至少为2的顶点集合

•        对于每个顶点,维护三个属性:

•        degree 邻居的个数

•        degree2 邻居中度为2的顶点数

•        id     编号

Pseudo-code

•        initialize V0, V1, V>=2 and (degree, degree2, id) of each node

•        while G is not empty

•        if V0 is not empty

•        choose v ∈ V0 with the smallest id

•        output v, delete v from V0 and G

•        else if V1 is not empty

•        choose v ∈ V1 with the smallest id, and find the neighbor u of v

•        output v, delete v from V0 and G, delete u from V1(or V>=2) and G

•        else

•        choose v ∈ V>=2 with the largest (degree, degree2, id)

•        delete v from V>=2 and G

索引的维护

•        需要注意的是,每个顶点的属性以及顶点集合V0、V1和V>=2并非一成不变。

•        当从图中删去某个顶点u时,u邻居的degree均会减一;如果u的degree恰好为2,那么u邻居的degree2也会减一。

•        如果某个邻居v的degree恰好从3减少到2或从2减到1,那么还会进一步影响到v的邻居的degree2属性。

•        对于那些degree减一的顶点,还需要相应地更新V0、V1和V>=2

Delete Node u from G

•        for v ∈ Neighbor(u)

•        v.degree decreases by one

•        if u.degree == 2 then v.degree2 decreases by one

•        if v.degree == 0

•        move v from V1 to V0

•        else if v.degree == 1

•        move v from V>=2 to V1

•        find the only neighbor w of v

•        w.degree2 decreases by one

•        else if v.degree == 2

•        for w ∈ Neighbor(v) do w.degree2 increases by one

2)复杂度分析

V0和V1 {node_id}

•        插入、删除顶点,但每个顶点最多一次;

•        查询id最小的顶点。

•        顶点数量O(N)

•        插入删除操作次数O(N)

•        查询最值次数O(N)

V>=2   {<node_id, value>}

•        初始化之后不会再插入顶点;

•        删除顶点,每个最多一次;

•        查询属性值最大的顶点;

•        修改一个点的属性值。

•        顶点数量O(N)

•        删除操作次数O(N)

•        查询最值次数O(N)

•        修改属性次数O(M)

3)可以使用的数据结构

•        堆、线段树、平衡树等等……

•        增、删、改、查都可以在O(logN)复杂度内完成

•        时间复杂度:O((N+M)logN)

•        懒得敲一个的话就用经济实惠的priority_queue好了。虽然不能直接进行删除或修改,但可以用懒更新的方式解决。即等到取用最值的时候,再判断该顶点是否已经被删除或属性已经被修改过了。

#include<queue>
#include<cstdio>
const int N=1e5+;
const int M=N*;
template <typename T>
inline void read(T &x){
T f=;char ch=getchar();x=;
while(ch<''||ch>''){if(ch=='-')f=-;ch=getchar();}
while(ch>=''&&ch<=''){x=x*+ch-'';ch=getchar();}
x*=f;
}
struct node{
int id,degree,nxt2;
node(int id=,int degree=,int nxt2=):id(id),degree(degree),nxt2(nxt2){}
bool operator <(const node &a){ // id < nxt2 < degree
return degree!=a.degree?degree<a.degree:nxt2!=a.nxt2?nxt2<a.nxt2:id<a.id;
}
}b[N];
template<class nodeT>
struct segtree{
int n;nodeT* a;
segtree(){}
segtree(int _n,const nodeT* b):n(_n){
a=new nodeT[n<<|];
build(,,n,b);
}
#define lch k<<1
#define rch k<<1|1
#define max(a,b) ((a)<(b)?b:a)
inline void updata(int k){
a[k]=max(a[lch],a[rch]);
}
void build(int k,int l,int r,const nodeT* b){
if(l==r){
a[k]=b[l];
return ;
}
int mid=l+r>>;
build(lch,l,mid,b);
build(rch,mid+,r,b);
updata(k);
}
void change(int k,int l,int r,int p,const nodeT &v){
if(l==r){
a[k]=v;
return ;
}
int mid=l+r>>;
if(p<=mid) change(lch,l,mid,p,v);
else change(rch,mid+,r,p,v);
updata(k);
}
inline void change(int p,const nodeT &v){
change(,,n,p,v);
}
inline void del(int p){
nodeT t(-,-,-);
change(,,n,p,t);
}
inline nodeT& query(){
return a[];
}
#undef lch
#undef rch
#undef max(a,b)
};
int cnt,ans[N];
int n,m,tot,to[M],next[M],head[N],degree[N];int del[N];
std::priority_queue<int,std::vector<int>,std::greater<int> >q0,q1;
inline void add(int x,int y){
to[++tot]=y;next[tot]=head[x];head[x]=tot;
}
inline void addedge(int x,int y){
add(x,y);degree[x]++;
add(y,x);degree[y]++;
}
inline void Erase(int u,segtree<node> &tree){
del[u]=;
tree.del(u);
for(int j=head[u],v;j;j=next[j]){
if(del[v=to[j]]) continue;
b[v].degree--;
if(b[u].degree==) b[v].nxt2--;
tree.change(v,b[v]);
if(b[v].degree==||b[v].degree==){
for(int k=head[v],w;k;k=next[k]){
if(del[w=to[k]]) continue;
b[w].nxt2+=b[v].degree*-;
tree.change(w,b[w]);
}
}
if(b[v].degree==) q0.push(v);
if(b[v].degree==) q1.push(v);
}
}
inline void Init(){
read(n);read(m);
for(int i=,x,y;i<=m;i++) read(x),read(y),addedge(x,y);
}
inline void Solve(){
for(int i=;i<=n;i++) b[i].id=i,b[i].degree=degree[i],b[i].nxt2=;
for(int i=;i<=n;i++){
if(degree[i]==){
for(int j=head[i];j;j=next[j]){
b[to[j]].nxt2++;
}
}
}
segtree<node> tree(n,b);
for(int i=;i<=n;i++){
if(!degree[i]){
del[i]=;
tree.del(i);
ans[++cnt]=i;
}else if(degree[i]==) q1.push(i);
}
for(int u,v;;){
if(!q0.empty()){
u=q0.top();q0.pop();
if(del[u]) continue;
del[u]=;
tree.del(u);
ans[++cnt]=u;
}
else if(!q1.empty()){
u=q1.top();q1.pop();
if(del[u]) continue;
for(int i=head[u];i;i=next[i]) if(!del[v=to[i]]) break;
Erase(u,tree);
Erase(v,tree);
ans[++cnt]=u;
}
else{
int tid=tree.query().id;
if(~tid) Erase(tid,tree);else break;
}
}
for(int i=;i<=cnt;i++) printf("%d\n",ans[i]);
}
int main(){
freopen("greedy.in","r",stdin);
freopen("greedy.out","w",stdout);
Init();
Solve();
return ;
}

“知乎杯”2018 CCF 大学生计算机系统与程序设计竞赛 贪心算法(greedy)的更多相关文章

  1. “知乎杯”2018 CCF 大学生计算机系统与程序设计竞赛 绝地求生(battleground)

    /* Style Definitions */ table.MsoNormalTable {mso-style-name:普通表格; mso-tstyle-rowband-size:0; mso-ts ...

  2. “知乎杯”2018 CCF 大学生计算机系统与程序设计竞赛 分组加密器(encryption)

    分组加密器(encryption) 题解点这里 #include<map> #include<stack> #include<vector> #include< ...

  3. 中国大学生计算机系统与程序设计竞赛 CCF-CCSP-2016 选座( ticket_chooser )

    选座( ticket_chooser ) 不会正解,欢迎讨论 //60分 #include<cstdio> #define max(a,b) (a)>(b)?a:b #define ...

  4. 中国大学生计算机系统与程序设计竞赛 CCF-CCSP-2017 串行调度(serial)

    串行调度(serial) 除等价条件, 根据题意设置限制条件,然后求字典序最小拓扑序. 简洁版 #include<bits/stdc++.h> using namespace std; ; ...

  5. "字节跳动杯"2018中国大学生程序设计竞赛-女生专场 Solution

    A - 口算训练 题意:询问 $[L, R]$区间内 的所有数的乘积是否是D的倍数 思路:考虑分解质因数 显然,一个数$x > \sqrt{x} 的质因子只有一个$ 那么我们考虑将小于$\sqr ...

  6. "字节跳动杯"2018中国大学生程序设计竞赛-女生专场

    口算训练 #include <iostream> #include <algorithm> #include <cstring> #include <cstd ...

  7. “纽劢科技杯”第十六届同济大学程序设计竞赛暨上海邀请赛同步赛 J-张老师的游戏

    传送门 题目描述     在空闲时间,张老师习惯性地和菜哭武玩起了取石子游戏,这次的游戏规则有些不同,在他们面前有n堆石子,其中,第i堆石子的个数为a[i],现在制定规则如下:     从张老师开始, ...

  8. CTF 湖湘杯 2018 WriteUp (部分)

    湖湘杯 2018 WriteUp (部分),欢迎转载,转载请注明出处! 1.  CodeCheck(WEB) 测试admin ‘ or ‘1’=’1’# ,php报错.点击登录框下面的滚动通知,URL ...

  9. 2018 ACM 国际大学生程序设计竞赛上海大都会部分题解

    题目链接 2018 ACM 国际大学生程序设计竞赛上海大都会 下午午休起床被同学叫去打比赛233 然后已经过了2.5h了 先挑过得多的做了 .... A题 rand x*n 次点,每次judge一个点 ...

随机推荐

  1. Luogu2481 SDOI2010 代码拍卖会 DP、组合

    传送门 神仙DP 注意到\(N \leq 10^{18}\),不能够直接数位DP,于是考虑形成的\(N\)位数的性质. 因为低位一定不会比高位小,所以所有满足条件的\(N\)位数一定是不超过\(9\) ...

  2. 【写法】为什么if判断中,值要倒着写

    =============================================== 2019/8/27_第1次修改                       ccb_warlock == ...

  3. js获取对象的属性个数

    for (var i = 0; i < dt.length; i++) { if (Object.keys(dt[i]).length <= 1) { dt.splice(i, 1); i ...

  4. Java自学-数组 Arrays

    java.util.Arrays类常用方法 Arrays是针对数组的工具类,可以进行 排序,查找,复制填充等功能. 大大提高了开发人员的工作效率. 步骤 1 : 数组复制 与使用System.arra ...

  5. Python进阶----反射(四个方法),函数vs方法(模块types 与 instance()方法校验 ),双下方法的研究

    Python进阶----反射(四个方法),函数vs方法(模块types 与 instance()方法校验 ),双下方法的研究 一丶反射 什么是反射: ​ 反射的概念是由Smith在1982年首次提出的 ...

  6. Linux系统:保证数据安全落盘

    在很多IO场景中,我们经常需要确保数据已经安全的写到磁盘上,以便在系统宕机重启之后还能读到这些数据.但是我们都知道,linux系统的IO路径还是很复杂的,分为很多层,每一层都可能会有buffer来加速 ...

  7. Django:基于调试组插件go-debug-toolbar

    1.django-debug-toolbar 介绍 django-debug-toolbar 是一组可配置的面板,可显示有关当前请求/响应的各种调试信息,并在单击时显示有关面板内容的更多详细信息.返回 ...

  8. JAVA基础之事务

    世界万事无简单一说, 每个事情基本上由多个小的事情来完成.有的事情会存在若小的事情不能同时完成的情况就取消所有的小的事情,直至都完成达到预期的效果才算完成!这样就用到了事务操作.在所有的sql语句完成 ...

  9. swiper-动态更改数据后轮播点击或拖动失效

    出现的问题: 1.swiper不能自动切换(设置了autoplay). 2.数据不匹配(需要加载的数据以改变,但是swiper里面的数据出现错误). 3.数据匹配过后,永远切换不到第一条数据. 4.根 ...

  10. 记录axios在IOS上不能发送的问题

    最近 遇到 了axios在IOS上无法发送的问题,测试 了两个 苹果 机,IOS10上不能发送,IOS12可以,百度了下,找到了解决方法.记录下吧 首先引入qs,这个安装axios也已经有了吧:然后在 ...