不是圖論
Time Limit: 3000/1000MS (Java/Others) Memory Limit: 65535/65535KB (Java/Others)
給出一個nn個點,mm條邊的有向圖。每個點上有分值,經過這個點時可以獲得一定的分數。
一個點可以經過多次,但是一個點上的分數只能獲得一次。
問最多能獲得多少分數,起點任選。
1<=nn<=30000,1<=mm<=100000
Input
輸入包含多組數據
每組數據第一行爲nn,mm
接下來nn行,每行有一個數,表示第ii個節點的分值。
接下來mm行,每行有兩個數aa、bb,表示有一條從aa到bb的有向邊
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;
}