这大概是我写过的除了树剖以外最长的代码了吧

首先看到有向图和重复经过等敏感词应该能想到先tarjan后缩点了吧

首先有一个naive的想法,既然我们要求只能走一次返回原点,那我们就正着反着建两遍图,分别处理出1到其他点的所能经过的最多点数和其他点到1经过的最大点数,之后找到那些和1有正边或反边相连的点,之后逆行这一条边,取一个max就好了

于是洋洋洒洒写了100多行发现连样例都过不了

本着交一交试试看的心态交了上去,发现还能过四个点

于是就去手画了一遍样例,发现自己真的是非常naive

样例是这个样子的

尽管很丑,但就勉强看看吧

我们发现按照刚才那个思路我们显然是要挂的

因为按照那样跑出来的结果是4,但这里的最佳方案应该是从1到那个缩好的点再到5,之后逆行一次走到3,之后走回1

这样我们如果只考虑能到到1的或只考虑能被1到达的,显然是不行的

这样不行怎么办,我们放到一起考虑就好了

如果一个能被1到达的点(比如说样例里的5)有一条边(当然这是一条反边)能到达一个能到达1的点,我们就可以把这两种情况一起考虑

同理一个能到达1的点有一条边(自然这是一条正边)和一个能被1到达的点相连,这两种情况也可以一起考虑

所以就是代码了

#include<iostream>
#include<cstring>
#include<cstdio>
#include<bitset>
#define re register
#define maxn 100001
using namespace std;
struct node
{
int v,nxt;
}e[maxn],e1[maxn],e2[maxn];
int head[maxn],head1[maxn],head2[maxn];
int dfn[maxn],low[maxn],st[maxn],belong[maxn],dp1[maxn],d[maxn],dp2[maxn];
int f1[maxn],f2[maxn];
int q[maxn],r[maxn],c[maxn];
bitset<maxn> f;//闲的没事干开了bitset
int n,m,top,k,p,num,num1,num2,mid;
inline void add_edge(int x,int y)
{
e[++num].v=y;
e[num].nxt=head[x];
head[x]=num;
}//原图
inline void add_edge_1(int x,int y)
{
e1[++num1].v=y;
e1[num1].nxt=head1[x];
head1[x]=num1;
}//缩点后新图建正边
inline void add_edge_2(int x,int y)
{
e2[++num2].v=y;
e2[num2].nxt=head2[x];
head2[x]=num2;
}//缩点后新图建反边
inline int read()
{
char c=getchar();
int x=0;
while(c<'0'||c>'9') c=getchar();
while(c>='0'&&c<='9')
x=(x<<3)+(x<<1)+c-48,c=getchar();
return x;
}
void tarjan(int x)
{
dfn[x]=low[x]=++k;
f[x]=1;
st[++top]=x;
for(re int i=head[x];i;i=e[i].nxt)
if(!dfn[e[i].v]) tarjan(e[i].v),low[x]=min(low[x],low[e[i].v]);
else if(f[e[i].v]) low[x]=min(low[x],dfn[e[i].v]);
if(dfn[x]==low[x])
{
p++;
do
{
mid=st[top--];
f[mid]=0;
d[p]++;//记录新点点权
belong[mid]=p;//记录好每一个点属于哪一个缩完点后的新点
}while(x!=mid);
}
}
int main()
{
n=read();
m=read();
int x,y;
for(re int i=1;i<=m;i++)
{
x=read();
y=read();
add_edge(x,y);
}
for(re int i=1;i<=n;i++)
if(!dfn[i]) tarjan(i);//缩点!
for(re int i=1;i<=n;i++)
for(re int j=head[i];j;j=e[j].nxt)
if(belong[i]!=belong[e[j].v])
{
r[belong[e[j].v]]++,add_edge_1(belong[i],belong[e[j].v]);//建正图
c[belong[i]]++,add_edge_2(belong[e[j].v],belong[i]);//建反图
}
f[belong[1]]=1;//我们开一个标记数组,标记那些点可以被1到达,拓扑排序的时候只有这些点才进行动规,其余的点只做删边操作
dp1[belong[1]]=d[belong[1]];
int tot=0;
for(re int i=1;i<=p;i++)
if(!r[i]) q[++tot]=i;
for(re int i=1;i<=tot;i++)
{
for(re int j=head1[q[i]];j;j=e1[j].nxt)
{
r[e1[j].v]--;
if(f[q[i]])
{
f[e1[j].v]=1;
dp1[e1[j].v]=max(dp1[e1[j].v],dp1[q[i]]+d[e1[j].v]);
//dp1[i]表示从1到i形成的最大点权
}
if(!r[e1[j].v]) q[++tot]=e1[j].v;
}
}
int ans=0;
for(re int i=head1[belong[1]];i;i=e1[i].nxt)
ans=max(ans,dp1[e1[i].v]);
for(re int i=1;i<=p;i++)
f1[i]=f[i];//记录那些点可以被1到达
tot=0;
memset(q,0,sizeof(q));
f.reset();//bitset清零
f[belong[1]]=1;//标记同理,表示这个点可以到达1
dp2[belong[1]]=d[belong[1]];
for(re int i=1;i<=p;i++)
if(!c[i]) q[++tot]=i;
for(re int i=1;i<=tot;i++)
{
for(re int j=head2[q[i]];j;j=e2[j].nxt)
{
c[e2[j].v]--;
if(f[q[i]])
{
f[e2[j].v]=1;
dp2[e2[j].v]=max(dp2[e2[j].v],dp2[q[i]]+d[e2[j].v]);
//dp2[i]表示i这个点到1形成的最大点权
}
if(!c[e2[j].v]) q[++tot]=e2[j].v;
}
}
for(re int i=head2[belong[1]];i;i=e2[i].nxt)
ans=max(ans,dp2[e2[i].v]);
for(re int i=1;i<=p;i++)
f2[i]=f[i];//记录那些点可以到达1
for(re int i=1;i<=p;i++)
if(f1[i])//这个点可以被1到达
{
for(re int j=head2[i];j;j=e2[j].nxt)//逆行一次
if(f2[e2[j].v]) ans=max(ans,dp1[i]+dp2[e2[j].v]-d[belong[1]]);//由于两次dp都把1所在的强联通分量的点权算了进去,所以要减去一个1所在的强联通分量的点权
}
for(re int i=1;i<=p;i++)
if(f2[i])
{
for(re int j=head1[i];j;j=e1[j].nxt)
if(f1[e1[j].v]) ans=max(ans,dp2[i]+dp1[e1[j].v]-d[belong[1]]);
}//同理
ans=max(d[belong[1]],ans);//如果一谁都到达不了,谁也到不了,那么答案就是1的点权了
printf("%d",ans);
return 0;
}

【[USACO15JAN]草鉴定Grass Cownoisseur】的更多相关文章

  1. 洛谷 P3119 [USACO15JAN]草鉴定Grass Cownoisseur 解题报告

    P3119 [USACO15JAN]草鉴定Grass Cownoisseur 题目描述 约翰有\(n\)块草场,编号1到\(n\),这些草场由若干条单行道相连.奶牛贝西是美味牧草的鉴赏家,她想到达尽可 ...

  2. 洛谷——P3119 [USACO15JAN]草鉴定Grass Cownoisseur

    P3119 [USACO15JAN]草鉴定Grass Cownoisseur 题目描述 In an effort to better manage the grazing patterns of hi ...

  3. [USACO15JAN]草鉴定Grass Cownoisseur(分层图+tarjan)

    [USACO15JAN]草鉴定Grass Cownoisseur 题目描述 In an effort to better manage the grazing patterns of his cows ...

  4. 洛谷 P3119 [USACO15JAN]草鉴定Grass Cownoisseur (SCC缩点,SPFA最长路,枚举反边)

    P3119 [USACO15JAN]草鉴定Grass Cownoisseur 题目描述 In an effort to better manage the grazing patterns of hi ...

  5. 【洛谷P3119】[USACO15JAN]草鉴定Grass Cownoisseur

    草鉴定Grass Cownoisseur 题目链接 约翰有n块草场,编号1到n,这些草场由若干条单行道相连.奶牛贝西是美味牧草的鉴赏家,她想到达尽可能多的草场去品尝牧草. 贝西总是从1号草场出发,最后 ...

  6. P3119 [USACO15JAN]草鉴定Grass Cownoisseur

    题目描述 In an effort to better manage the grazing patterns of his cows, Farmer John has installed one-w ...

  7. luogu P3119 [USACO15JAN]草鉴定Grass Cownoisseur

    题目描述 In an effort to better manage the grazing patterns of his cows, Farmer John has installed one-w ...

  8. 洛谷—— P3119 [USACO15JAN]草鉴定Grass Cownoisseur || BZOJ——T 3887: [Usaco2015 Jan]Grass Cownoisseur

    http://www.lydsy.com/JudgeOnline/problem.php?id=3887|| https://www.luogu.org/problem/show?pid=3119 D ...

  9. 洛谷3119 [USACO15JAN]草鉴定Grass Cownoisseur

    原题链接 显然一个强连通分量里所有草场都可以走到,所以先用\(tarjan\)找强连通并缩点. 对于缩点后的\(DAG\),先复制一张新图出来,然后对于原图中的每条边的终点向新图中该边对应的那条边的起 ...

  10. Luogu 3119 [USACO15JAN]草鉴定Grass Cownoisseur

    思路很乱,写个博客理一理. 缩点 + dp. 首先发现把一个环上的边反向是意义不大的,这样子不但不好算,而且相当于浪费了一次反向的机会.反正一个强连通分量里的点绕一遍都可以走到,所以我们缩点之后把一个 ...

随机推荐

  1. Ajax知识点复习

    1. ajax是什么? * asynchronous javascript and xml:异步的js和xml * 它能使用js访问服务器,而且是异步访问! * 服务器给客户端的响应一般是整个页面,一 ...

  2. 移动端Push推送

    移动端Push推送 移动端开发逃不掉要做推送,这里给出服务端一种省时省力的解决方案. iOS:PushSharp.Apple.苹果有自己的推送服务,我们按照规则推送数据就好.这里我选取PushShar ...

  3. java对象中含有Integer类型字段转json字符串问题

    问题:对于含有Integer类型字段的java对象,在通过下面这种方式转为json字符串时,Integer类型的字段如果为空的情况下,会默认转化为0,但是我想让它为空的时候直接转化为null,不要默认 ...

  4. SQL SEVERE 基本用法 1

    知识点: 数据库的存储结构分为逻辑存储结构和物理存储结构两种, 其中逻辑存储结构指是由那些信息组成,物理存储结构是指如何在磁盘上存储数据库文件的. 数据库文件由数据文件和事务日志文件组成,一个数据库至 ...

  5. How to limit Dialog's max height?

    1. We can make it to play trick in code. At Dialog's show function, after app has set contentView, w ...

  6. centos自带python2.6无法使用pip命令

    1.首先检查linux有没有安装python-pip包,直接执行 yum install python-pip,或者 which pip 我的已经安装了 2.没有可用软件包 python-pip.就执 ...

  7. csharp:.net 3.5 using System.Runtime.Serialization.Json read json

    using System; using System.Collections.Generic; using System.Linq; using System.Web; using System.We ...

  8. python垃圾回收机制(Garbage collection)

    由于面试中遇到了垃圾回收的问题,转载学习和总结这个问题. 在C/C++中采用用户自己管理维护内存的方式.自己管理内存极其自由,可以任意申请内存,但也为大量内存泄露.悬空指针等bug埋下隐患. 因此在现 ...

  9. spring cglib 与 jdk 动态代理

    1. 概述 JDK动态代理是利用java反射机制 生成一个实现接口的匿名类, 在调用具体方法前调用InvocationHandler来处理 Cglib动态代理是 利用asm开源包 把被代理类的clas ...

  10. after() 和 remove() 实现替换

    <div class="replacedDiv">this is the replaced div</div> <script>         ...