题意: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;
}