【洛谷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条边有向图,每个点有一个权值,求一条路径,使路径经过的点权值之和最大.你只需要求出这个权值和. 允许多次经过一条边或者一个点,但是,重复经过的点,权值只 ...
随机推荐
- 『居善地』接口测试 — 12、Moco框架介绍
目录 1.Mock功能介绍 2.Moco框架介绍 3.Moco框架在接口测试中的作用 4.Moco框架的优点 5.Moco框架的下载与启动 (1)Moco框架的下载 (2)Moco框架的启动 1.Mo ...
- 微软发布了Visual Studio 2022 Preview 1 以及.NET 6 Preview 5
Microsoft 今天宣布了Visual Studio 2022 的第一个预览版,并且同时也发布了.NET 6 Preview 5. https://devblogs.microsoft.com/v ...
- PAT甲级 1093 Count PAT‘s (25 分) 状态机解法
题目 原题链接 The string APPAPT contains two PAT's as substrings. The first one is formed by the 2nd, the ...
- JDK并发包一
JDK并发包一 同步控制是并发程序必不可少的重要手段,synchronized是一种最简单的控制方法.但JDK提供了更加强大的方法----重入锁 重入锁 重入锁使用java.util.concurre ...
- mturoute 最大传输单元路由检测Host
mturoute检测mtu字符 下载地址:https://www.elifulkerson.com/projects/mturoute.php mturoute.exe ...
- 性能分析之用户数(线程数)/响应时间/TPS的关系
最近在写一些东西的时候,把一些内容整理了一下. 在考虑压力工具中的用户数(有些工具中称为线程数,本文后续都用"用户数"来说明).响应时间.TPS三者之间的关系时,想到之前也有人问起 ...
- 百炼 POJ2393:Yogurt factory【把存储费用用递推的方式表达】
2393:Yogurt factory 总时间限制: 1000ms 内存限制: 65536kB 描述 The cows have purchased a yogurt factory that m ...
- Fiber 树的构建
我们先来看一个简单的 demo: import * as React from 'react'; import * as ReactDOM from 'react-dom'; class App ex ...
- 地图可视化神器keplergl新增对jupyter lab 3.0的支持
就在几天前,地图可视化神器kepler.gl面向Python的接口库keplergl迎来了新的0.3.0版本更新. 虽然官方文档还并未及时更新相关的内容说明,但我在快速地试用之后发现,现在的keple ...
- Linux中date的用法
一.命令格式:date [参数]... [+格式]二.命令功能:date 可以用来显示或设定系统的日期与时间.三.命令格式:%H 小时(以00-23来表示). %I 小时(以01-12来表示). %K ...