不是图论
Time Limit: 3000/1000MS (Java/Others) Memory Limit: 65535/65535KB (Java/Others)
给出一个 n n个点, m m条边的有向图。每个点上有分值,经过这个点时可以获得一定的分数。
一个点可以经过多次,但是一个点上的分数只能获得一次。
问最多能获得多少分数,起点任选。
1<= n n<=30000,1<= m m<=100000
Input
输入包含多组数据
每组数据第一行为 n n, m m
接下来 n n行,每行有一个数,表示第 i i个节点的分值。
接下来 m m行,每行有两个数 a a、 b b,表示有一条从 a a到 b b的有向边
Output
每组数据输出一行,每行仅有一个整数:可以获得的最多的分数。
题解:首先可以把同一个强连通分量看作一个点,分数为分量里点的分数之和,按照拓扑序,跑dp,具体看代码;
#include<bits/stdc++.h>
#define MAXN 30005
using namespace std;
int info[MAXN],info2[MAXN];
vector<int> to,to2,NEXT,next2;
int STACK[MAXN],dfn[MAXN],low[MAXN],belong[MAXN],instack[MAXN],sc[MAXN],vis[MAXN],ssc[MAXN],dp[MAXN];
int cnt,scnt,top,n,m;
set<int> st[MAXN];queue<int> q;
void add(int u,int v)
{
to.push_back(v);
NEXT.push_back(info[u]);
info[u]=to.size()-1;
}
void tarjan(int v)
{
int m,t;
dfn[v]=low[v]=++cnt;
instack[v]=1;
STACK[top++]=v;
for(int i=info[v];i!=-1;i=NEXT[i])
{
int j=to[i];
if(!dfn[j])
{
tarjan(j);
low[v]=min(low[v],low[j]);
}
else if(instack[j])
low[v]=min(low[v],dfn[j]);
}
if(dfn[v]==low[v])
{
scnt++;
do
{
t=STACK[--top];
instack[t]=0;
belong[t]=scnt;
ssc[scnt]+=sc[t];
}while(t!=v);
}
}
void solve()
{
for(int i=1;i<=n;i++)
{
if(!dfn[i])
tarjan(i);
}
}
void init()
{
memset(info,-1,sizeof(info));
memset(info2,-1,sizeof(info2));
memset(instack,0,sizeof(instack));
memset(ssc,0,sizeof(ssc));
to.clear();to2.clear();NEXT.clear();next2.clear();
memset(vis,0,sizeof(vis));
memset(dfn,0,sizeof(dfn));
cnt=scnt=top=0;
}
int main()
{
int u,v;
while(scanf("%d%d",&n,&m)!=EOF)
{
init();
for(int i=1;i<=n;i++)
scanf("%d",&sc[i]);
for(int i=1;i<=m;i++)
{
scanf("%d%d",&u,&v);
add(u,v);
}
solve();
for(int i=1;i<=n;i++)
{
for(int j=info[i];j!=-1;j=NEXT[j])
{
if(belong[i]!=belong[to[j]]&&!st[i].count(to[j]))
{
int u=belong[i],v=belong[to[j]];
to2.push_back(v);
next2.push_back(info2[u]);
info2[u]=to2.size()-1;
st[u].insert(v);
}
}
}
for(int i=1;i<=scnt;i++)
dp[i]=ssc[i];
for(int i=0;i<to2.size();i++)
vis[to2[i]]++;
for(int i=1;i<=scnt;i++)
if(!vis[i])
q.push(i);int ans=-1;
while(!q.empty())
{
int u=q.front();q.pop();ans=max(ans,dp[u]);
for(int i=info2[u];i!=-1;i=next2[i])
{
int v=to2[i];
dp[v]=max(dp[v],dp[u]+ssc[v]);
ans=max(ans,dp[v]);
vis[v]--;
if(!vis[v])
q.push(v);
}
}
printf("%d\n",ans);
}
return 0;
}