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

首先看到有向图和重复经过等敏感词应该能想到先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. Truncated incorrect DOUBLE value: 'NO_REFUND'

    解决办法:Mysql中,如果一个字段是字符串,则一定要加单引号 问题原因: `item_refund_state` ) NOT NULL item_refund_state字段的类型是varchar但 ...

  2. ReSharper+Devexpress 删除光标之后的换行

    echo. >"$(ProjectDir)\Properties\licenses.licx" 官方链接

  3. Telerik 控件本地化

    一共四种方式: Localization using built-in resources Resource keys Localization using ResourceManager Local ...

  4. Mysql插入Emoji表情出错

    Caused by: java.sql.SQLException: Incorrect at com.mysql.jdbc.SQLError.createSQLException(SQLError.j ...

  5. SQL SERVER 2012修改数据库名称(包括 db.mdf 名称的修改)

    假设原来数据库名为db,附加数据库为db.mdf和db_log.ldf.需要改成dbt,及dbt.mdf和dbt_log.ldf. 步骤: .首先把原来的数据库进行备份(选择数据库->右键-&g ...

  6. 反编译DLL文件

    我们平时在工作中经常会遇到一些已经被编译后的DLL,而且更加麻烦是没有源代码可以进行修改,只能针对这个DLL的文件进行修改才能得到我们想要的结果:本文将通过一个实例来演示如果完成一个简单的修改;我们将 ...

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

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

  8. VC中BSTR、Char*、CString和CComBSTR类型的转换

    原文:http://blog.csdn.net/wanghaihao_1/article/details/37498689 1.char*转换成CString 若将char*转换成CString,除了 ...

  9. 【Anaconda】windows安装报错:UnicodeDecodeError解决方法

    UnicodeDecodeError: 'utf8' codec can't decode byte 0xce in position 11: invalid continuation byte 解决 ...

  10. Vue2.0中的Ajax请求

    Vue可以借助于vue-resource来实现Ajax请求 http请求报文 浏览器与服务器数据交互是遵循http协议的,当浏览器要访问服务器的时候,浏览器需要将相关请求数据提交给服务器. 格式分为: ...