P1137 旅行计划
如果不是这个数据范围,其实暴力搜索就可以的(比如每个点一次Dj或者一次全局变量爆搜),一开始蒟蒻就写的暴力,也就用了大概几分钟,但是很显然暴力是过不了的qwq……
那么常规想法:
对于这样的题,首先肯定是要反着存图,其次一定是要开一个vis来判断是否这个点走过,如果走过的话就可以直接利用这个走过的点的最优数据来更新现在的点(因为这个vis过的点曾经一定是被走过且走到头了的),关键就是怎么表示这个走过的点对多能向外延伸多少点……
蒟蒻想了很长时间,最后终于有了灵感:
对于dfs回溯,如果到头(head[u]==0)那么这个ans一定是1,直接赋值,那么在回溯的时候,这个节点的最优解就是这个点现有的解和刚刚那个回溯前的点的最大值,再用这个点作为一个回溯点,再更新它的父亲节点。
有一个细节,至关重要,很致命!!!(注意!)
对于一个找过的vis,我们发现后直接利用曾经计算过的解直接更新后,不可以!不可以!不可以!return!!!
因为return会直接不找这个点的其它儿子节点而返回的!!!(蒟蒻就因为这个卡了无数次,打了无数次表最后才发现的QAQ)
代码来啦:
#include<cstdio> #include<iostream> using namespace std; #define maxn 100005 int head[maxn],to[2*maxn],nxt[2*maxn],ans[maxn],from[2*maxn]; int n,m,cnt; bool vis[maxn]; void add(int a,int b) { to[++cnt]=b; nxt[cnt]=head[a]; head[a]=cnt; from[cnt]=a; } void find(int u) { if(head[u]==0) { vis[u]=1; ans[u]=1; return ; } for(int i=head[u]; i; i=nxt[i]) { if(vis[to[i]]) { ans[from[i]]=max(ans[from[i]],ans[to[i]]+1); vis[from[i]]=1; continue; } vis[to[i]]=1; vis[from[i]]=1; find(to[i]); ans[from[i]]=max(ans[from[i]],ans[to[i]]+1); } } int main() { scanf("%d%d",&n,&m); for(int i=1; i<=m; i++) { int a,b; scanf("%d%d",&a,&b); add(b,a); } for(int i=1; i<=n; i++) find(i); for(int i=1; i<=n; i++) printf("%d\n",ans[i]); return 0; }