【[USACO15JAN]草鉴定Grass Cownoisseur】
这大概是我写过的除了树剖以外最长的代码了吧
首先看到有向图和重复经过等敏感词应该能想到先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】的更多相关文章
- 洛谷 P3119 [USACO15JAN]草鉴定Grass Cownoisseur 解题报告
		P3119 [USACO15JAN]草鉴定Grass Cownoisseur 题目描述 约翰有\(n\)块草场,编号1到\(n\),这些草场由若干条单行道相连.奶牛贝西是美味牧草的鉴赏家,她想到达尽可 ... 
- 洛谷——P3119 [USACO15JAN]草鉴定Grass Cownoisseur
		P3119 [USACO15JAN]草鉴定Grass Cownoisseur 题目描述 In an effort to better manage the grazing patterns of hi ... 
- [USACO15JAN]草鉴定Grass Cownoisseur(分层图+tarjan)
		[USACO15JAN]草鉴定Grass Cownoisseur 题目描述 In an effort to better manage the grazing patterns of his cows ... 
- 洛谷 P3119 [USACO15JAN]草鉴定Grass Cownoisseur (SCC缩点,SPFA最长路,枚举反边)
		P3119 [USACO15JAN]草鉴定Grass Cownoisseur 题目描述 In an effort to better manage the grazing patterns of hi ... 
- 【洛谷P3119】[USACO15JAN]草鉴定Grass Cownoisseur
		草鉴定Grass Cownoisseur 题目链接 约翰有n块草场,编号1到n,这些草场由若干条单行道相连.奶牛贝西是美味牧草的鉴赏家,她想到达尽可能多的草场去品尝牧草. 贝西总是从1号草场出发,最后 ... 
- P3119 [USACO15JAN]草鉴定Grass Cownoisseur
		题目描述 In an effort to better manage the grazing patterns of his cows, Farmer John has installed one-w ... 
- luogu P3119 [USACO15JAN]草鉴定Grass Cownoisseur
		题目描述 In an effort to better manage the grazing patterns of his cows, Farmer John has installed one-w ... 
- 洛谷—— 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 ... 
- 洛谷3119 [USACO15JAN]草鉴定Grass Cownoisseur
		原题链接 显然一个强连通分量里所有草场都可以走到,所以先用\(tarjan\)找强连通并缩点. 对于缩点后的\(DAG\),先复制一张新图出来,然后对于原图中的每条边的终点向新图中该边对应的那条边的起 ... 
- Luogu 3119 [USACO15JAN]草鉴定Grass Cownoisseur
		思路很乱,写个博客理一理. 缩点 + dp. 首先发现把一个环上的边反向是意义不大的,这样子不但不好算,而且相当于浪费了一次反向的机会.反正一个强连通分量里的点绕一遍都可以走到,所以我们缩点之后把一个 ... 
随机推荐
- YII框架一个请求的生命周期
			用户向入口脚本 web/index.php 发起请求. 入口脚本加载应用配置并创建一个应用实例去处理请求. 应用通过请求组件解析请求的路由. 应用创建一个控制器实例去处理请求. 控制器创建一个操作实例 ... 
- Firebird hash join
			Firebird 现可支持哈希连接(hash join),各中大型数据库,哈希连接已成为平常,相对于循环嵌套连接(Nested Loop Join),在数据量较大的情况下,哈希连接性能较好. 由于 F ... 
- 全面理解面向对象的JavaScript
			转载:http://justcoding.iteye.com/blog/2019293 原文:http://www.ibm.com/developerworks/cn/web/1304_zengyz_ ... 
- swoole安装
			转自:http://blog.csdn.net/u014207604/article/details/49926207 Windows 下安装 swoole 具体步骤: Swoole,原本不支持在Wi ... 
- LinearLayout中的android:layout_garvity的center_vertical和center_horizontal
			当LinearLayout的排列方向是 horizontal时,只有垂直方向上的对齐方式才会生效.因为此时水平方向上的长度是不固定的,每添加一个控件,水平方向上的长度都会改变,因而无法指定该方向上的对 ... 
- 第一行代码 10.2使用HTTP协议访问网络 HttpURLConnection代码中的问题
			实现HttpURLConnection代码的时候,遇到了问题. 怎样点击途中Send Request按钮,没有任何改变. 最后将MainActivity中的一段代码URL url = new URL( ... 
- unity3d之控制人物转向移动并播放动画
			tip:transition 勾选Has Exit Time B动画播放完毕后就可以自己返回A不用代码控制.因为想做一个小人静止时 隔两秒会摆动小手的特效. 附上代码参考: using UnityEn ... 
- python文件操作各种模式和常用方法总结r r+ rb r+b
			1.读,r r+ rb r+b read() 全部读取 read(n) 读取一部分 r模式下:n 个字符. rb模式下:n个 字节. readline() 按行读取. readlines() 返回个列 ... 
- centos  yum安装常用命令
			安装killall命令 yum install -y psmisc 安装sz(下载)和rz(上传)命令 yum install -y lrzsz 安装 ifconfig 命令 yum install ... 
- js权威指南学习笔记(二)表达式与运算符
			1.数组初始化表达式 数组直接量中的列表逗号之间的元素可以省略,这时省略的空位会填充undefined.如: 2 2 1 var arr = [1,,,,,6]; 2 ... 
