洛谷3119 草鉴定(tarjan)
题目大意
约翰有\(n\)块草场,编号\(1\)到\(n\),这些草场由若干条单行道相连。奶牛贝西是美味牧草的鉴赏家,她想到达尽可能多的草场去品尝牧草。
贝西总是从\(1\)号草场出发,最后回到\(1\)号草场。她想经过尽可能多的草场,贝西在通一个草场只吃一次草,所以一个草场可以经过多次。因为草场是单行道连接,这给贝西的品鉴工作带来了很大的不便,贝西想偷偷逆向行走一次,但最多只能有一次逆行。问,贝西最多能吃到多少个草场的牧草。
\(n,m\le 10^5\)
QwQ一开始看这个题 没有思路呀
首先一定是\(tarjan\)消环,对吧
我们可以考虑,如果只能反向走一条边,那我们可以枚举这个边呀,然后算一算\(ans\)
那么对于一条边\(u->v\),如果我们选择反向走,我们能获得的收益是\(val[v]+valn[u]-sval[1]\) 其中\(val[x]\)表示从1到x的最大收益,\(valn[x]\)表示\(x\)到1的最大收益(这个可以通过建反图来算)
之所以减去\(sval[1]\),因为1这个联通快的贡献会算两边,按照题意,应该只算一遍。
为什么这样是对,为什么可以保证没有别的点的贡献被算两遍。
我们可以这么考虑,假设存在一个联通快他的贡献被计算了两次,那么他一定能到1,也能从1到,那么就说明存在环,但是因为我们在一开始\(tarjan\)缩点过,所以不会存在这么一个点,所以这样计算贡献是没有错的
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
#include<queue>
using namespace std;
inline int read()
{
int x=0,f=1;char ch=getchar();
while (!isdigit(ch)) {if (ch=='-') f=-1;ch=getchar();}
while (isdigit(ch)) {x=(x<<1)+(x<<3)+ch-'0';ch=getchar();}
return x*f;
}
const int maxn = 1e5+1e2;
const int maxm = 1e6+1e2;
int point[maxn],nxt[maxm],to[maxm],sval[maxn];
int s[maxn],top;
int bel[maxn],roo[maxn];
int tot;
int cnt;
int n,m;
int x[maxm],y[maxm];
int low[maxn],dfn[maxn];
int vis[maxn],scc;
void addedge(int x,int y)
{
nxt[++cnt]=point[x];
to[cnt]=y;
point[x]=cnt;
}
void tarjan(int x)
{
dfn[x]=low[x]=++tot;
s[++top]=x;
vis[x]=1;
for (int i=point[x];i;i=nxt[i])
{
int p = to [i];
if (!dfn[p])
{
tarjan(p);
low[x]=min(low[x],low[p]);
}
else
if(vis[p]) low[x]=min(low[x],dfn[p]);
}
if (low[x]==dfn[x])
{
scc++;
while (s[top+1]!=x)
{
//++scc;
bel[s[top]]=scc;
roo[s[top]]=x;
sval[scc]++;
vis[s[top]]=0;
top--;
}
}
}
int num[maxm];
int dis[maxn],disn[maxn];
queue<int> q;
void spfa(int s)
{
memset(dis,0,sizeof(dis));
memset(vis,0,sizeof(vis));
vis[s]=1;
dis[s]=sval[bel[s]];
q.push(s);
while (!q.empty()){
int x = q.front();
q.pop();
vis[x]=0;
for (int i=point[x];i;i=nxt[i])
{
int p = to[i];
if (dis[p]<dis[x]+sval[bel[p]])
{
dis[p]=dis[x]+sval[bel[p]];
if (!vis[p])
{
vis[p]=1;
q.push(p);
}
}
}
}
}
void spfa1(int s)
{
memset(disn,0,sizeof(disn));
memset(vis,0,sizeof(vis));
vis[s]=1;
disn[s]=sval[bel[s]];
q.push(s);
while (!q.empty()){
int x = q.front();
q.pop();
vis[x]=0;
for (int i=point[x];i;i=nxt[i])
{
int p = to[i];
if (disn[p]<disn[x]+sval[bel[p]])
{
disn[p]=disn[x]+sval[bel[p]];
if (!vis[p])
{
vis[p]=1;
q.push(p);
}
}
}
}
}
int main()
{
n=read(),m=read();
for (int i=1;i<=m;i++) {
x[i]=read(),y[i]=read();
addedge(x[i],y[i]);
}
for (int i=1;i<=n;i++)
{
if (!dfn[i]) tarjan(i);
}
//for (int i=1;i<=n;i++) cout<<sval[i]<<endl;
memset(point,0,sizeof(point));
cnt=0;
for (int i=1;i<=m;i++)
{
if (bel[x[i]]!=bel[y[i]])
{
addedge(roo[x[i]],roo[y[i]]);
num[i]=1;
}
}
spfa(roo[1]);
memset(point,0,sizeof(point));
cnt=0;
for (int i=1;i<=m;i++)
{
if (num[i]) addedge(roo[y[i]],roo[x[i]]);
}
spfa1(roo[1]);
int ans=0;
//for (int i=1;i<=n;i++) cout<<dis[i]<<" "<<disn[i]<<endl;
for (int i=1;i<=m;i++)
{
if (!num[i]) continue;
if (dis[roo[y[i]]] && disn[roo[x[i]]])
ans=max(ans,dis[roo[y[i]]]+disn[roo[x[i]]]-sval[bel[roo[1]]]);
}
cout<<ans;
return 0;
}
洛谷3119 草鉴定(tarjan)的更多相关文章
- 洛谷P3119草鉴定
题目 草鉴定,tarjan可以用来缩点,优化spfa的时间, 缩点之后就是一个\(DAG\)了,因此完全可以用来跑spfa上的最长路,然后枚举每条边,查看是否这条边的两个节点分别可以到达起点所在的强连 ...
- 洛谷P3119 草鉴定
这个题调了一天.. 传送门 读完题目之后我们不难想出这个题是个tarjan缩点问题,因为尽量多的经过草场,所以一号点所在的强连通分量里左右的点都是不需要在进行走逆向边,所能到达的. 然后问题就落在怎么 ...
- 洛谷 1262 间谍网络 Tarjan 图论
洛谷 1262 图论 tarjan 并不感觉把这道题目放在图的遍历中很合适,虽然思路比较简单但是代码还是有点多的,, 将可收买的间谍的cost值设为它的价格,不可购买的设为inf,按照控制关系连图,T ...
- 洛谷3119 [USACO15JAN]草鉴定Grass Cownoisseur
原题链接 显然一个强连通分量里所有草场都可以走到,所以先用\(tarjan\)找强连通并缩点. 对于缩点后的\(DAG\),先复制一张新图出来,然后对于原图中的每条边的终点向新图中该边对应的那条边的起 ...
- luogu3119/bzoj3887 草鉴定 (tarjan缩点+spfa)
首先缩一波点,就变成了一个DAG,边权是出点的大小 那我们走到某个点的时候可能会有两种状态:已经走过反边或者没走过 于是就把一个点拆成两层(x和x+N),第二层的点表示我已经走过反边了,每层中的边和原 ...
- Luogu3119 草鉴定-Tarjan+Topsort
Solution 简单的$Tarjan$题. 有大佬现成博客 就不写了 → 传送门 Code #include<cstdio> #include<cstring> #inclu ...
- 洛谷 P3119 [USACO15JAN]草鉴定Grass Cownoisseur 解题报告
P3119 [USACO15JAN]草鉴定Grass Cownoisseur 题目描述 约翰有\(n\)块草场,编号1到\(n\),这些草场由若干条单行道相连.奶牛贝西是美味牧草的鉴赏家,她想到达尽可 ...
- 【洛谷P3119】[USACO15JAN]草鉴定Grass Cownoisseur
草鉴定Grass Cownoisseur 题目链接 约翰有n块草场,编号1到n,这些草场由若干条单行道相连.奶牛贝西是美味牧草的鉴赏家,她想到达尽可能多的草场去品尝牧草. 贝西总是从1号草场出发,最后 ...
- 洛谷——P3119 [USACO15JAN]草鉴定Grass Cownoisseur
P3119 [USACO15JAN]草鉴定Grass Cownoisseur 题目描述 In an effort to better manage the grazing patterns of hi ...
随机推荐
- 跨域@RequestBody@RequestParam 和JSON.stringify
- Learning ROS: rostopic pub yaml demo
官方Tutorials中例程的等效命令: rostopic pub -1 /turtle1/cmd_vel geometry_msgs/Twist -- '{linear:[2.0, 0.0, 0.0 ...
- Linux centos7 scp命令
1. 命令简介 scp(secure copy) 是 linux 系统下基于 ssh 登陆进行安全的远程文件拷贝命令,可以在两台 Linux 主机进行复制操作 # 语法 scp [-1246BCpqr ...
- Linux触摸驱动分析
测试平台 宿主机平台:Ubuntu 12.04.4 LTS 目标机:Easy-ARM IMX283 目标机内核:Linux 2.6.35.3 触摸屏基础知识 一.结构 上图是电阻触摸屏的一个侧面剖视图 ...
- app自动化定位:UIautomation的用法
UIautomation定位的优点: 速度比xpath定位快,UIautomation是Android的工作引擎 缺点: 没有idea提示 UIautomation使用方法: AndroidDrive ...
- Intel® QAT加速卡之Linux上编程说明
QAT Software for Linux 1. Introduction 该程序员指南提供了有关软件体系结构和使用指南的信息. 相关的英特尔QAT软件库文档中记录了有关使用英特尔QuickAssi ...
- 基于Ubuntu18.04一站式部署(python-mysql-redis-nginx)
基于Ubuntu18.04一站式部署 Python3.6.8的安装 1. 安装依赖 ~$ sudo apt install openssl* zlib* 2. 安装python3.6.8(个人建议从官 ...
- JAVA安全基础之代理模式(一)
JAVA安全基础之代理模式(一) 代理模式是java的一种很常用的设计模式,理解代理模式,在我们进行java代码审计时候是非常有帮助的. 静态代理 代理,或者称为 Proxy ,简单理解就是事情我不用 ...
- 使用Jmeter执行接口自动化测试-如何初始化清空旧数据
需求分析: 每次执行完自动化测试,我们不会执行删除接口把数据删除,而需要留着手工测试,此时会导致下次执行测试有旧数据 我们手工可能也会新增数据,导致下次执行自动化测试有旧数据 下面介绍两种清空数据的方 ...
- three.js 在模型上移动相机
需求: 根据鼠标点击位置相机进行相应的移动, 方案: 1.实际要解决的问题就是 相机以及相机朝向位置 的坐标更新 2.使用 TWEEN 组件 优化两个点切换的补间动画 3.获取鼠标点击的位置 获取鼠标 ...