【洛谷P5008 逛庭院】tarjan缩点+贪心
既然没有题解,那么我就来提供给一份。
--
首先我们看到数据范围。妈耶!数据这么大,一开始还想用个DP来做,但是看着就不行,那么根据这个数据范围,我们大致可以猜到这道题的算法是一个贪心,那么我们怎么贪呢?
我们首先还是先画一个图:
样例解释一下:
我们取的点是\(3\),\(5\),\(7\)。
看到题目,因为\(1\)号节点的入度为0,那么就一定不能选择\(1\)号节点,那么接下来可以供我们选择的最大的权值的点也就只有\(3\),\(5\),\(7\)号节点,那么我们就来一个贪心策略:对每一个节点的权值进行排序,然后将所有不能取的节点全部不算,剩下的就都取最大的那几个。
以下是\(30\)分骗分程序
# include <bits/stdc++.h>
# define Ri register int
# define for1(i,a,b) for(Ri i(a);i<=b;++i)
# define for2(i,a,b) for(Ri i(a);i>=b;--i)
using namespace std;
inline int read ()
{
int w = 0,x = 0;
char ch = 0;
while (!isdigit(ch)) { w |= ch =='-'; ch = getchar();}
while (isdigit(ch)) { x = (x<<1) + (x<<3) + (ch ^ 48); ch = getchar(); }
return w ? -x : x;
}
const int Maxm = 2000004;
const int Maxn = 5000004;
int Nedge, n, m, k;
int head[Maxm], ind[Maxn];
struct node{
int v ,id ,ind ;
}a[5000004];
bool cmp (node a,node b)
{
return a.v > b.v;
}
int main()
{
n = read(),m = read(),k = read(); Nedge = 1;
for1(i ,1 ,n ) a[i].v = read(),a[i].id = i;
for1(i ,1 ,m )
{
int u = read(),v = read();
a[v].ind ++;
}
sort (a + 1 , a + 1 + n , cmp);
int cnt = 0 , ans = 0;
for1(i ,1 ,n)
{
if (a[i].ind == 0) continue;
else
{
ans += a[i].v;
cnt ++;
if (cnt == k) break;
}
}
printf ("%d\n", ans);
return 0;
}
但是这个贪心一定是错的。
为什么
我们来想一下,如果可以去掉的节点,是某一个接下来可以取的节点的唯一一个入边来源,那么这个一定会影响后面的答案,这个点也就不取了,所以我们就不能这样做。
那么我们应该怎么做呢?
这个时候我们就需要 胆大心细地思考题目了。我是好好听了出征大会的
其实也就只需要在这个贪心的基础上,加上一个契机,这个契机就是让当前这个删去的点,可以不对后面的点产生影响。
正解策略是:我们首先缩点,然后找到入度为0的环,删去这个环中权值最小的点,然后从小到大排序,取前k大的点。
我们先给一个缩点的模板吧!
inline void tarjan(int u)
{
dfn[u] = low[u] = ++ dep;
vis[u] = 1;
S[top++] = u;
for (int i = head[u]; i != -1; i = edge[i].next )
{
int v = edge[i].to;
if (!dfn[v])
{
tarjan(v);
low[u] = Min(low[u] ,low[v]);
}
else if (vis[v]) low[u] = Min(low[u] ,low[v]);
}
int j;
if (dfn[u] == low[u])
{
sum ++;
do
{
j = S[ -- top];
belong[j] = sum ;
vis [j] = 0;
}while (u != j) ;
}
}
解释
那么我们就需要一个手段,使得这个这个点成为一个删去和不删去,不会影响答案得到东西:这个玩意的名字叫做缩点。
为什么我们会想到缩点,我们得从DAG中的环开始说起。
早在。。因为在有向图中,每一个点都是可以互相到达的,那么所以这个有向图中的每一个点都是有入度的,没有人反驳吧!,所以这个里面的点都是可以随意取的,但是要注意attention:当你这这个环是\(0\)的入度时,那么你就不能随意取掉最后一个点了,因为你这个最后一个点可能就没有入度了,那么我们为了保证所有的点都可以取到,我们就将这个环内的权值最小的点删去,那么这样就可以保证这个环断开后,这个点集中的点就可以随便取了。
那么还有一个问题,也就是如果是一个节点的缩点?
其实也是一个道理,我就不解释了,也就是把这个点删掉,反正这个点完全没有用。
以下是AC代码(新的码风本人感觉还是挺好看的QAQ)
# include <bits/stdc++.h>
# define Ri register int
# define for1(i,a,b) for(Ri i(a);i<=b;++i)
# define for2(i,a,b) for(Ri i(a);i>=b;--i)
# define ms(a,b) memset(a,b,sizeof(a))
using namespace std;
typedef long long LL;
const int M = 2000005;
struct Edge{
int to ,next;
}edge[M];
int dfn[M], vis[M], low[M], S[M], head[M] ,belong[M] ,ind[M];
int dep, top, sum , n ,m ,k ,Nedge;
struct node{
int v ,id ;
}a[M];
inline int read() //快读
{
int w = 0,x = 0;
char ch = 0;
while (!isdigit(ch))
{
w |= ch == '-';
ch = getchar();
}
while (isdigit(ch))
{
x = (x<<1) + (x<<3) + (ch^48);
ch = getchar();
}
return w ? -x : x ;
}
inline int Min(int n,int m) //三目取min
{
return n < m ? n : m;
}
inline void Add_Edge(int u ,int v) //链式前向星
{
edge[Nedge] = (Edge) {v ,head[u]} ;
head[u] = Nedge++;
}
inline void tarjan(int u) //tarjan缩点模板
{
dfn[u] = low[u] = ++ dep;
vis[u] = 1;
S[top++] = u;
for (int i = head[u]; i != -1; i = edge[i].next )
{
int v = edge[i].to;
if (!dfn[v])
{
tarjan(v);
low[u] = Min(low[u] ,low[v]);
}
else if (vis[v]) low[u] = Min(low[u] ,low[v]);
}
int j;
if (dfn[u] == low[u])
{
sum ++;
do
{
j = S[ -- top];
belong[j] = sum ;
vis [j] = 0;
}while (u != j) ;
}
}
inline bool cmp1(node a,node b) //从小到大排序
{
return a.v < b.v;
}
inline bool cmp2(node a,node b) //从大到小排序
{
return a.v > b.v;
}
int main()
{
ms(head ,-1);
ms(dfn ,0);
ms(vis ,0);
ms(belong ,0);
sum = 0,dep = 0,top = 0;
n = read(),m = read(),k = read();
for1(i ,1 ,n) a[i].v = read(),a[i].id = i;
for1(i ,1 ,m)
{
int u = read(),v = read();
Add_Edge(u , v);
}
for1(i ,1 ,n)
{
if (!dfn[i]) tarjan(i); // 缩一波点
}
for1(i ,1 ,n)
{
for (int j = head[i]; j != -1; j = edge[j].next)
{
int v = edge[j].to;
if ( belong[i] != belong[v] ) ind[belong[v]] ++;
}
}//统计当前缩完点后的每个点的入度
sort(a + 1, a + 1 + n ,cmp1);
for1(i ,1 ,n)
{
if (ind[belong[a[i].id]] == 0)
{
a[i].v = 0;
ind[belong[a[i].id]] = 1;
}
}//删去一个联通块中权值最小的点
sort(a + 1 , a + 1 + n ,cmp2);
LL ans = 0, cnt = 0;
for1(i ,1 ,n) //计算我们的答案
{
ans += a[i].v;
cnt ++ ;
if (cnt == k) break;
}
printf ("%lld\n", ans);
return 0;
}
【洛谷P5008 逛庭院】tarjan缩点+贪心的更多相关文章
- luogu5008 逛庭院 (tarjan缩点)
首先如果这是一个DAG,我按照拓扑序倒着去选,一定能选到所有入度不为0的点 然后考虑有环的情况 我们拎出来一个强连通分量 先假设它缩点以后是没有入度的 那我最后它里面一定至少剩一个不能选 因为就剩一个 ...
- tarjan缩点练习 洛谷P3387 【模板】缩点+poj 2186 Popular Cows
缩点练习 洛谷 P3387 [模板]缩点 缩点 解题思路: 都说是模板了...先缩点把有环图转换成DAG 然后拓扑排序即可 #include <bits/stdc++.h> using n ...
- 洛谷P3387 【模板】缩点 题解
背景 今天\(loj\)挂了,于是就有了闲情雅致来刷\(luogu\) 题面 洛谷P3387 [模板]缩点传送门 题意 给定一个\(n\)个点\(m\)条边有向图,每个点有一个权值,求一条路径,使路径 ...
- 洛谷 P3387 【模板】缩点 DAGdp学习记
我们以洛谷P3387 [模板]缩点 来学习DAGdp 1.这道题的流程 //伪代码 for i->n if(i未被遍历) tarjan(i) 缩点() DAGdp() 完成 首先tarjan这部 ...
- [洛谷P1638]逛画展
[洛谷P1638]逛画展 题目大意: 有\(n(n\le10^6)\)个格子,每个格子有一种颜色.颜色种数为\(m(m\le2000)\).求包含所有颜色的最小区间. 思路: 尺取法裸题. 思路: # ...
- 洛谷P2507 [SCOI2008]配对 题解(dp+贪心)
洛谷P2507 [SCOI2008]配对 题解(dp+贪心) 标签:题解 阅读体验:https://zybuluo.com/Junlier/note/1299251 链接题目地址:洛谷P2507 [S ...
- 洛谷 1262 间谍网络 Tarjan 图论
洛谷 1262 图论 tarjan 并不感觉把这道题目放在图的遍历中很合适,虽然思路比较简单但是代码还是有点多的,, 将可收买的间谍的cost值设为它的价格,不可购买的设为inf,按照控制关系连图,T ...
- 洛谷P3953 逛公园(NOIP2017)(最短/长路,拓扑排序,动态规划)
洛谷题目传送门 又是一年联赛季.NOIP2017至此收官了. 这个其实是比较套路的图论DP了,但是细节有点恶心. 先求出\(1\)到所有点的最短路\(d1\),和所有点到\(n\)的最短路\(dn\) ...
- 洛谷P3387 【模板】缩点
题目背景 缩点+DP 题目描述 给定一个n个点m条边有向图,每个点有一个权值,求一条路径,使路径经过的点权值之和最大.你只需要求出这个权值和. 允许多次经过一条边或者一个点,但是,重复经过的点,权值只 ...
随机推荐
- 一篇文章通俗易懂的让你彻底理解 Java 注解
很多Java程序员,对Java的注解一知半解,更有甚者,有的人可能连注解是什么都不知道 本文我们用最简单的 demo , 最通俗最短的语言,带你了解注解到底是什么? 先来简单回顾一下基础,我们知道,J ...
- 谁能干掉了if else
很多人觉得自己写的是业务代码,按照逻辑写下去,再把公用的方法抽出来复用就可以了,设计模式根本就没必要用,更没必要学. 一开始的时候,我也是这么想,直到我遇到... 举个例子 我们先看一个普通的下单拦截 ...
- 从 SQL 到 MongoDB,这一篇就够了
很多开发者首次接触数据库(通常是在高校课堂)的概念,或者说接触第一个数据库,通常是 SQL 数据库,而现在,NoSQL 数据库后来居上,很多原 SQL 数据的使用者难免有转向 NoSQL 的需求.而作 ...
- SQL 利用存储过程实现对表数据有则更新无则添加(转)
初学存储过程,发现这篇文章简单易懂,特意转载,地址 http://blog.csdn.net/luotuomianyang/article/details/52013144 如果某一操作包含大量的T- ...
- 信息熵,交叉熵与KL散度
一.信息熵 若一个离散随机变量 \(X\) 的可能取值为 \(X = \{ x_{1}, x_{2},...,x_{n}\}\),且对应的概率为: \[p(x_{i}) = p(X=x_{i}) \] ...
- 计算机网络的参考模型与5G协议
一.分层思想 二.OSI七层参考模型 三.FPC/IP五层模型 四.数据的封装过程与PDU(协议数据单元) 五.数据的解封装过程 六.各层间通信与设备与层的对应关系 七.总结 一.分层思想 将复杂的 ...
- 铂金07:整齐划一-CountDownLatch如何协调多线程的开始和结束
欢迎来到<并发王者课>,本文是该系列文章中的第20篇. 在上一篇文章中,我们介绍了Condition的用法.在本文中,将为你介绍CountDownLatch的用法.CountDownLat ...
- 最新Unity 与Android 交互通信(基于Unity 2019.4 和 Android Studio 4.1.1)
原文章链接:https://blog.csdn.net/woshihaizeiwang/article/details/115395519 CLSays:网上找了一圈,真的是很多都不能用,要么太老,要 ...
- 关于asp.net中Repeater控件的一些应用
在Asp.net中,我是比较喜欢用Repeater这个控件,刚刚遇到的一个问题,怎么实现单击 <asp:LinkButton>,通过后台的单击事件获取同一行数据中的其他数据(对象). 1, ...
- 本地无法访问虚拟机的tomcat
查看 firewalld防火墙 是否开启 命令: firewall-cmd --state 如果是 running 关闭 firewalld防火墙命令: service firewalld stop ...