乍看似乎可以用拓扑排序,但由于数据量很大,一般会超时,至少我没去用。我的做法是加一个超级出发点0,将原图的各个分量组合起来,然后进行记忆化搜索。其中 dis[i],记录的是标号为i的结点到出度为0的点的最长距离,因此dis[0]即为所求。
一开始时是用spfa()来做,一直超时,由于有负权,没敢用dijk+heap。因此,这时记忆化搜索就有用了。
以下是代码:
- #include<cstdio>
#include<cstring>
using namespace std;
const int N=101000;
const int M=1100000;
const __int64 inf=(__int64)1<<60;
__int64 max(__int64 a,__int64 b) {return a>b?a:b;} - struct node
{
int u,v;
int next;
}edge[2*M];
int head[N],num;
__int64 val[N];
int ind[N],out[N];
bool inst[N];
int n,m; - void init()
{
for(int i=0;i<=n+1;i++)
{
head[i]=-1;
ind[i]=out[i]=0;
}
num=0;
} - void addege(int u,int v)
{
edge[num].u=u;
edge[num].v=v;
edge[num].next=head[u];
head[u]=num++;
} - bool vis[N];
__int64 dis[N];
void dfs(int s)
{
int i,j;
if(out[s]==0)
{
dis[s]=0;
return ;
}
for(i=head[s];i!=-1;i=edge[i].next)
{
int v=edge[i].v;
if(!vis[v])
{
vis[v]=1;
dfs(v);
dis[s]=max(dis[s],dis[v]+val[v]);
}
else
{
dis[s]=max(dis[s],dis[v]+val[v]);
}
}
} - int main()
{
while(scanf("%d%d",&n,&m)==2)
{
init();
int i,j;
int a,b;
for(i=1;i<=n;i++)
scanf("%I64d",&val[i]);
while(m--)
{
scanf("%d%d",&a,&b);
addege(a,b);
out[a]++;
ind[b]++;
}
for(i=1;i<=n;i++)
{
if(ind[i]==0)
{
addege(0,i);
out[0]++;
}
dis[i]=-inf;
vis[i]=0;
}
dis[0]=-inf;
vis[0]=1;
dfs(0);
printf("%I64d/n",dis[0]);
}
return 0;
}