这是一道很简单的模版题(尽管我调了好长时间)……QAQ
那那那就总结思路嘞:
乍一看,觉得dfs就可以,于是便有这样的代码:
#include<cstdio> #include<cstring> #include<iostream> using namespace std; int to[100005],head[100005],nxt[100005],cnt; bool b[100005]; int sum; int n,m; void add(int a,int t) { cnt++; to[cnt]=t; nxt[cnt]=head[a]; head[a]=cnt; } void dfs(int x) { for(int i=head[x]; i; i=nxt[i]) { if(b[to[i]]==0) { b[to[i]]=1; sum=max(sum,to[i]); dfs(to[i]); b[to[i]]=0; } else return ; } } int main() { scanf("%d%d",&n,&m); int a,t; for(int i=1; i<=m; i++) { scanf("%d%d",&a,&t); add(a,t); } for(int i=1; i<=n; i++) { memset(b,0,sizeof(b)); sum=0; b[i]=1; dfs(i); sum=max(sum,i); printf("%d ",sum); } return 0; }
但是呐,这个代码其实有很大漏洞的,那就是:
void dfs(int x) { for(int i=head[x]; i; i=nxt[i]) { if(b[to[i]]==0) { b[to[i]]=1; sum=max(sum,to[i]); dfs(to[i]); b[to[i]]=0; } else return ; } }
在这里,只要有一个b[]没满足dfs就会返回,会遗漏情况…另外,above all,会超时…
那么怎么不超时呐???
特别鸣谢ssy等人的鼎力支持,使蒟蒻的我想到一个全新的方案,我们可以逆向思考:那就是从后往前找!!!(震惊!)
还有这种操作???
是的!
代码呈现:
#include<cstdio> #include<cstring> #include<iostream> using namespace std; int to[100005],head[100005],nxt[100005],cnt; bool b[100005]; int sum,ans[100005],now; int n,m; void add(int a,int t) { cnt++; to[cnt]=t; nxt[cnt]=head[a]; head[a]=cnt; } void dfs(int x) { if(ans[x]) return ; ans[x]=now; for(int i=head[x];i;i=nxt[i]) { if(ans[to[i]]==0) dfs(to[i]); } } int main() { scanf("%d%d",&n,&m); int a,t; for(int i=1; i<=m; i++) { scanf("%d%d",&a,&t); add(t,a); } for(int i=n;i>=1;i--) { memset(b,0,sizeof(b)); now=i; dfs(now); } for(int i=1;i<=n;i++) printf("%d ",ans[i]); return 0; }
假设有10个点,那么从10这个点往回找,只要能到达,就给这个点赋上值,那么下一次搜9的时候,赋值的点一定是最优点,碰到就直接return,如果没赋值,则证明这个点不能到10,最优解一定是9。这样使不必要的情况被有效避免,就达到了剪枝的目的。注意add要反过来。
>\<~