poj 3160 Father Christmas flymouse
http://poj.org/problem?id=3160
题意:给出一个有向图,每个点有一个点权,点权可能是正也可能为负,一个人从某点出发,沿着一些路,访问结点,或者仅仅是路过这个结点,而不去访问,最后求他能访问到的最大的点权和。
思路:在有向图里,经过一个点,可以访问,也可以不访问,所以可以把环上的值都取完,其它的能达到就取。因此先进行缩点聚值,然后dfs+记忆化求最大值。

#include<set> #include<map> #include<stack> #include<queue> #include<cmath> #include<bitset> #include<string> #include<climits> #include<cstdio> #include<vector> #include<utility> #include<cstdlib> #include<cstring> #include<iostream> #include<algorithm> #define IN puts("in") #define OUT puts("out") #define FR(x) freopen(x,"r",stdin) #define FW(x) freopen(x,"w",stdout) #define MSET(x,y) memset(x,y,sizeof(x)) #define ST system("pause") using namespace std; const int maxn = 30005; struct nd { int u,v,next; }edge[maxn*5]; int head[maxn],vis[maxn],dfn[maxn],low[maxn],val[maxn],belong[maxn],c[maxn],st[maxn],in[maxn],hash[maxn]; int ecnt,cnt,idx,tp,ans; void add(int u,int v) { edge[ecnt].u = u; edge[ecnt].v = v; edge[ecnt].next = head[u]; head[u] = ecnt++; } void tarjan(int u) { int i,v; dfn[u] = low[u] = ++idx; vis[u] = 1; st[++tp] = u; for(i = head[u]; i != -1; i = edge[i].next) { v = edge[i].v; if(!dfn[v]){ tarjan(v); low[u] = min(low[v],low[u]); }else if(vis[v]) low[u] = min(dfn[v],low[u]); } if(low[u]==dfn[u]) { ++cnt; do{ v = st[tp--]; vis[v] = 0; belong[v] = cnt; c[cnt] += val[v]; }while(v!=u); } } void dfs(int u,int sum) { int i,v; if(sum<=hash[u])return ; hash[u] = sum; ans = max(ans,sum); for(i = head[u]; i != -1; i = edge[i].next) dfs(edge[i].v,sum+c[edge[i].v]); } void processing() { int i,j,k,t,n,m,u,v; while(scanf("%d %d",&n,&m)==2) { for(i = 0; i < n; ++ i){scanf("%d",val+i);if(val[i]<0)val[i]=0;} MSET(c,0); MSET(belong,0); MSET(dfn,0); MSET(in,0); MSET(low,0); MSET(vis,0); MSET(head,-1); ecnt = cnt = idx = tp = 0; for(i = 0; i < m; ++ i) { scanf("%d %d",&u,&v); add(u,v); } for(i = 0; i < n; ++ i)if(!dfn[i])tarjan(i); k = ecnt; ecnt = 0; MSET(head,-1); for(i = 0; i < k; ++ i) { u = belong[edge[i].u]; v = belong[edge[i].v]; if(v!=u){add(u,v);in[v]++;} } ans = 0; MSET(hash,-1); for(i = 1; i <= cnt; ++ i) if(!in[i])dfs(i,c[i]); printf("%d\n",ans); } } int main() { processing(); return 0; }