[Usaco2015 Jan]Grass Cownoisseur Tarjan缩点+SPFA
考试的时候忘了缩点,人为dfs模拟缩点,没想到竟然跑了30分,RB爆发。。。
边是可以重复走的,所以在同一个强连通分量里,无论从那个点进入从哪个点出,所有的点一定能被一条路走到。 要使用缩点。
然后我们枚举每一条边,考虑如果将这条边反置的话,就是这条边的终点到1的点的权值(正向的)加上起点到1的点的权值(反向的);例:→→←→→
每个点到1的正向反向距离可以用两遍SPFA解决出来。
先使用tarjan缩点,记录每个点的权值,缩点后权值变为强连通分量中点的个数。缩完点之后重新建图,正向边存1,反向边存-1;
注意:在枚举每一条边求MAX时一定要判断它的起点和终点能否到达1。
#include<iostream> #include<cstdio> #include<cstring> #include<cmath> #include<queue> using namespace std; #define pos(i,a,b) for(int i=(a);i<=(b);i++) #define pos2(i,a,b) for(int i=(a);i>=(b);i--) #define N 501000 int n,m; struct haha { int next,to,w; }; haha edgechu[N],edge[N]; int head[N],headchu[N],cnt=1,cntchu=1,cntt,hea; int belong[N],low[N],dfn[N],ji=1,stack[N],instack[N]; int point[N]; void add(int u,int v,int w) { edge[cnt].to=v; edge[cnt].next=head[u]; edge[cnt].w=w; head[u]=cnt++; } void addchu(int u,int v,int w) { edgechu[cntchu].to=v; edgechu[cntchu].next=headchu[u]; edgechu[cntchu].w=w; headchu[u]=cntchu++; } void tarjan(int now) { low[now]=dfn[now]=ji; ji++; stack[++hea]=now; instack[now]=1; for(int v=headchu[now];v;v=edgechu[v].next) { int i=edgechu[v].to; if(dfn[i]==-1) { tarjan(i); low[now]=min(low[now],low[i]); } else if(instack[i]) low[now]=min(low[now],dfn[i]); } if(low[now]==dfn[now]) { cntt++; int temp; while(1) { temp=stack[hea--]; belong[temp]=cntt; point[cntt]++; instack[temp]=0; //cout<<"temp="<<temp<<" cntt="<<cntt<<endl; if(temp==now) break; } } } int diszheng[N],disfan[N]; int flag[N]; void spfazheng(int x) { queue<int> q; pos(i,1,n) diszheng[i]=0; memset(flag,0,sizeof(flag)); diszheng[x]=point[x]; q.push(x); flag[x]=1; int k; while(!q.empty()) { k=q.front(); for(int v=head[k];v;v=edge[v].next) { int i=edge[v].to; if(edge[v].w>0&&diszheng[i]<diszheng[k]+point[i]) { diszheng[i]=diszheng[k]+point[i]; if(!flag[i]) { q.push(i); flag[i]=1; } } } flag[q.front()]=0; q.pop(); } } void spfafan(int x) { queue<int> q; pos(i,1,n) disfan[i]=0; memset(flag,0,sizeof(flag)); disfan[x]=point[x]; q.push(x); flag[x]=1; int k; while(!q.empty()) { k=q.front(); for(int v=head[k];v;v=edge[v].next) { int i=edge[v].to; if(edge[v].w<0&&disfan[i]<disfan[k]+point[i]) { disfan[i]=disfan[k]+point[i]; if(!flag[i]) { q.push(i); flag[i]=1; } } } flag[q.front()]=0; q.pop(); } } struct qian { int from,to; }cun[N]; int road; int ans; int main() { //freopen("cown.in","r",stdin); //freopen("cown.out","w",stdout); scanf("%d%d",&n,&m); memset(dfn,-1,sizeof(dfn)); pos(i,1,m) { int x,y; scanf("%d%d",&x,&y); addchu(x,y,1); } pos(i,1,n) if(dfn[i]==-1) tarjan(i); pos(i,1,n) for(int v=headchu[i];v;v=edgechu[v].next) { int j=edgechu[v].to; if(belong[i]!=belong[j]) { add(belong[i],belong[j],1); add(belong[j],belong[i],-1); cun[++road].from=belong[i]; cun[road].to=belong[j]; } } spfafan(belong[1]);spfazheng(belong[1]); /*pos(i,1,cntt) cout<<"diszheng[i]="<<diszheng[i]<<" disfan[i]="<<disfan[i]<<endl;*/ pos(i,1,road) { if(diszheng[cun[i].to]>0&&disfan[cun[i].from]>0) ans=max(ans,diszheng[cun[i].to]+disfan[cun[i].from]-point[belong[1]]); //cout<<"ans="<<ans<<endl; } printf("%d",ans); //while(1); return 0; }
[Usaco2015 Jan]Grass Cownoisseur Tarjan缩点+SPFA的更多相关文章
- BZOJ 3887: [Usaco2015 Jan]Grass Cownoisseur tarjan + spfa
Code: #include <bits/stdc++.h> #define setIO(s) freopen(s".in","r",stdin) ...
- BZOJ3887 [Usaco2015 Jan] Grass Cownoisseur 【tarjan】【DP】*
BZOJ3887 [Usaco2015 Jan] Grass Cownoisseur Description In an effort to better manage the grazing pat ...
- [补档][Usaco2015 Jan]Grass Cownoisseur
[Usaco2015 Jan]Grass Cownoisseur 题目 给一个有向图,然后选一条路径起点终点都为1的路径出来,有一次机会可以沿某条边逆方向走,问最多有多少个点可以被经过? (一个点在路 ...
- bzoj3887: [Usaco2015 Jan]Grass Cownoisseur
题意: 给一个有向图,然后选一条路径起点终点都为1的路径出来,有一次机会可以沿某条边逆方向走,问最多有多少个点可以被经过?(一个点在路径中无论出现多少正整数次对答案的贡献均为1) =>有向图我们 ...
- BZOJ 3887/Luogu P3119: [Usaco2015 Jan]Grass Cownoisseur (强连通分量+最长路)
分层建图,反向边建在两层之间,两层内部分别建正向边,tarjan缩点后,拓扑排序求一次1所在强连通分量和1+n所在强联通分量的最长路(长度定义为路径上的强联通分量内部点数和).然后由于1所在强连通分量 ...
- [Usaco2015 Jan]Grass Cownoisseur 图论 tarjan spfa
先缩点,对于缩点后的DAG,正反跑spfa,枚举每条边进行翻转即可 #include<cstdio> #include<cstring> #include<iostrea ...
- BZOJ3887 [Usaco2015 Jan]Grass Cownoisseur[缩点]
首先看得出缩点的套路.跑出DAG之后,考虑怎么用逆行条件.首先可以不用,这样只能待原地不动.用的话,考虑在DAG上向后走,必须得逆行到1号点缩点后所在点的前面,才能再走回去. 于是统计从1号点缩点所在 ...
- 洛谷—— 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 ...
- [bzoj3887][Usaco2015 Jan]Grass Cownoisseur_trajan_拓扑排序_拓扑序dp
[Usaco2015 Jan]Grass Cownoisseur 题目大意:给一个有向图,然后选一条路径起点终点都为1的路径出来,有一次机会可以沿某条边逆方向走,问最多有多少个点可以被经过?(一个点在 ...
随机推荐
- Java NIO 核心组件学习笔记
背景知识 同步.异步.阻塞.非阻塞 首先,这几个概念非常容易搞混淆,但NIO中又有涉及,所以总结一下[1]. 同步:API调用返回时调用者就知道操作的结果如何了(实际读取/写入了多少字节). 异步:相 ...
- Chapter 7. Design and Performance
本章将对MPEG4及H.264的实现细节进行讲解和比对. Motion Estimation 衡量运动估计的好坏有三种函数(第228页):MSE,MAE和SAE,其中由于SAE运算速度最快所以采用的最 ...
- USACO Dynamic Programming (1)
首先看一下题目: Introduction Dynamic programming is a confusing name for a programming technique that drama ...
- solr的基本概念
一.solr的基本概念 大家可以把solr搜索引擎看成一个数据库,不过是基于内存的.它可以存储信息,并且根据你的查询条件返回你想要的信息. 1.collection和core的概念 collectio ...
- 本地服务器 windows server 2008 datacenter conn /as sysdba 提示 ora-01031 insufficient privileges
原因是需要把当前用户administrator(为例)添加到ora_dba组里. 服务器管理器--配置--本地用户和组--组
- 配置tomcat的远程调试
参考文档: http://jingyan.baidu.com/article/0320e2c1f4ef6b1b87507b06.html http://flyer2010.iteye.com/blog ...
- 微信小程序+OLAMI(欧拉蜜)自然语言API接口制作智能查询工具--快递、聊天、日历等
微信小程序最近比较热门,再加上自然语义理解也越来越被人关注,于是我想赶赶潮流,做一个小程序试试.想来想去快递查询应该是一种比较普遍的需求. 如果你也在通过自然语言接口做点什么,希望我的这篇博客能帮到你 ...
- python基础(7):元祖类型(赋值补充)
前面学了列表和字典,今天我们看一个和列表相似的类型元祖. 预习: 简单购物车 实现打印商品详细信息,用户输入商品名和购买个数,则将商品名,价格,购买个数加入购物列表,如果输入为空或其他非法输入则要求用 ...
- 流畅python学习笔记:第十一章:抽象基类
__getitem__实现可迭代对象.要将一个对象变成一个可迭代的对象,通常都要实现__iter__.但是如果没有__iter__的话,实现了__getitem__也可以实现迭代.我们还是用第一章扑克 ...
- 玩玩微信公众号Java版之准备
微信自2013年流行起来,现在的发展已经超过了我们的想象,那么对应的公众平台,小程序等都是让人眼前一亮的东西,这里来学习一下微信工作号的对接,实现为Java,希望大家一起学习! 这里大概描述一下所 ...