这道题错了好几次,没有看到一定从1号开始走。
题目的意思就是问你从一号开始走,最多可以吃多少草。
直接用到有向图的双连通的trajan算法给图缩点,
再重新新建一个缩完点之后的图,
然后直接从1号开始dfs就可以了。
#include<stdio.h> #include<string.h> #include<algorithm> #include<stack> using namespace std; const int N=20010; const int M=200020; int pnt[M],nxt[M],head[M],e; int pnt1[M],nxt1[M],head1[M],e1; int low[N],dfn[N],belong[N],pan[N],st[N]; int cost[N]; int n,m,top,depth,cnt; long long sum,maxk,num[N]; void AddEdge(int u,int v) { pnt[e]=v; nxt[e]=head[u]; head[u]=e++; } void AddEdge2(int u,int v) { pnt1[e]=v; nxt1[e]=head1[u]; head1[u]=e++; } void init() { cnt=top=depth=0; e=0; e1=0; sum=0; maxk=0; memset(head,-1,sizeof(head)); memset(head1,-1,sizeof(head1)); memset(dfn,0,sizeof(dfn)); memset(num,0,sizeof(num)); for(int i=0; i<=n; i++) pan[i]=belong[i]=0; } void dfs(int now) { st[top++]=now; dfn[now]=low[now]=++depth; pan[now]=1; for(int i=head[now]; i!=-1; i=nxt[i]) { if(!dfn[pnt[i]]) { dfs(pnt[i]); low[now]=min(low[now],low[pnt[i]]); } else if(pan[pnt[i]])//遇到回边的处理,如果是之前已经处理过的强连通分量的点就不管了。 low[now]=min(low[now],dfn[pnt[i]]); } if(low[now]==dfn[now]) { cnt++; int j; while(j=st[--top]) { pan[st[top]]=0; belong[st[top]]=cnt; if(j==now)break; } } return ; } void dfs2(int u,long long cc) { //printf("%d ",u); if(sum<cc)sum=cc; for(int i=head1[u]; i!=-1; i=nxt1[i]) { int v=pnt1[i]; dfs2(v,cc+num[v]); } } void print() { for(int i=1; i<=n; i++) num[belong[i]]+=cost[i]; for(int u=1; u<=n; u++) { for(int i=head[u]; i!=-1; i=nxt[i]) { int v=pnt[i]; if(belong[u]!=belong[v]) { // printf("ss %d %d\n",belong[u],belong[v]); AddEdge2(belong[u],belong[v]); } } } sum=0; dfs2(belong[1],num[belong[1]]);//1号点变成了变成缩点的belong[1]值。 maxk=max(maxk,sum); printf("%d\n",maxk); } int main() { scanf("%d%d",&n,&m); init(); for(int i=1; i<=n; i++) scanf("%d",&cost[i]); int u,v; for(int i=0; i<m; i++) { scanf("%d%d",&u,&v); AddEdge(u,v); } for(int i=1; i<=n; i++) if(!dfn[i]) dfs(i); print(); return 0; }