题意:flymouse要去送礼物,送的每个人有一定的反馈comfort值,有正有负,给一个有向图,
要你找出一条路径,沿着这个路径去送礼物可以使总的comfort值最大。
注意题意里面的一个关键点:flymouse经过每个房间时,可以选择进去或者不进去,所以我们可以把负值的comfort值赋为0。
思路:
先用tarjan算法处理一遍强连通分量。
然后缩点成有向无环图。
然后简单dp:对有向无环图的每个节点进行有返回值的dfs,对树节点dfs递归时,比较子节点的返回值,取较大的作为返回值。
思路正确但还是wa了很多次,原因出在dfs上,还是太菜了。
#include<iostream> #define min(a,b) (a<b?a:b) using namespace std; const int N=30005,M=150005; int n,m; int cft[N];// comfort struct Edge { int u,v,next; }edge[2*M]; int edgehead[N]; int k; int dfn[N],low[N]; int index; int stack[N]; bool instack[N]; int sp; int father[N]; int head[N]; int pth; struct { int u,v; }add[M]; int addn; void addedge(int u,int v) { edge[k].u=u; edge[k].v=v; edge[k].next=edgehead[u]; edgehead[u]=k++; } void tarjan(int now) { dfn[now]=low[now]=++index; stack[sp++]=now; instack[now]=true; for(int i=edgehead[now];i;i=edge[i].next) { int v=edge[i].v; if(!dfn[v]) { tarjan(v); low[now]=min(low[now],low[v]); } else if(instack[v]) { low[now]=min(low[now],dfn[v]); } } if(low[now]==dfn[now]) { int j; head[pth++]=now; do { j=stack[--sp]; instack[j]=false; father[j]=now; if(j!=now) cft[now]+=cft[j]; }while(j!=now); } } bool vis[N]; int dfs(int now) { int ret=0; int pre=0; for(int i=edgehead[now];i;i=edge[i].next) { int v=father[edge[i].v]; int u=now; if(u!=v)//&&!vis[v]) { //vis[v]=true; int tmp=dfs(v); if(tmp>ret) { ret=tmp; } //else //{ // vis[v]=false; //} } } return ret+cft[now]; } void solve() { for(int i=1;i<=n;i++) { if(!dfn[i]) { tarjan(i); } } for(int i=1;i<=n;i++) { for(int j=edgehead[i];j;j=edge[j].next) { int u=i; int v=edge[j].v; if(father[u]!=father[v]) { //addedge(father[u],father[v]); add[addn].u=father[u]; add[addn++].v=father[v]; } } } for(int i=1;i<addn;i++) addedge(add[i].u,add[i].v); int ans=0; for(int i=1;i<=pth-1;i++) { //memset(vis,0,sizeof(vis)); //vis[head[i]]=true; int ret=dfs(head[i]); if(ret>ans) ans=ret; } printf("%d\n",ans); } int main() { while(scanf("%d%d",&n,&m)!=EOF) { k=1; index=1; sp=1; pth=1; addn=1; memset(add,0,sizeof(add)); memset(cft,0,sizeof(cft)); memset(vis,0,sizeof(vis)); memset(head,0,sizeof(head)); memset(father,0,sizeof(father)); memset(instack,0,sizeof(instack)); memset(stack,0,sizeof(stack)); memset(dfn,0,sizeof(dfn)); memset(low,0,sizeof(low)); memset(edge,0,sizeof(edge)); memset(edgehead,0,sizeof(edgehead)); for(int i=1;i<=n;i++) { scanf("%d",&cft[i]); if(cft[i]<0) cft[i]=0; } int from,to; for(int i=1;i<=m;i++) { scanf("%d%d",&from,&to); addedge(from+1,to+1); } solve(); } return 0; }