很显然这道就是需要先求出强连通分量,然后缩点。缩点之后就是有向无环图了。实际上这之后,各种方法就都可以了。
已知的dp:1.通过拓扑序用一个队列来进行dp,图是原先的图
2.缩点后建新图时,将图反向建。然后对于每一个酒吧,记忆话搜索,到市中心的最短路(我用的这种方法)
spfa:缩点后跑spfa,求出到每一个酒吧的最长路(我不敢确定这样的复杂度,就没写这个)
#include<cstdio>
#include<cstring>
#include<cmath>
#include<cstdlib>
#include<stack>
using namespace std;
inline int read()
{
int ans,f=1;char ch;
while ((ch=getchar())<'0'||ch>'9') if (ch=='-') f=-1;
ans=ch-'0';
while ((ch=getchar())>='0'&&ch<='9') ans=ans*10+ch-'0';
return ans*f;
}
const int N=600005;
const int inf=0x7777ffff;
int n,m;
int val1[N],val2[N];
int dfn[N],low[N],size,pos[N],id;
int f[N],S,P;
struct aa
{
int to[N*2],pre[N*2],head[N],tot;
void addedge(int x,int y)
{
to[++tot]=y;pre[tot]=head[x];head[x]=tot;
}
}old,now;
void init()
{
n=read();m=read();
int x,y;
for (int i=1;i<=m;i++)
{
x=read();y=read();
old.addedge(x,y);
}
for (int i=1;i<=n;i++) val1[i]=read();
}
stack<int> s;
bool in[N];
void dfs(int u)
{
dfn[u]=low[u]=++id;
s.push(u);
in[u]=true;
for (int i=old.head[u];i;i=old.pre[i])
{
int v=old.to[i];
if (!dfn[v])
{
dfs(v);
low[u]=min(low[u],low[v]);
}
else if (in[v]) low[u]=min(low[u],dfn[v]);
}
if (dfn[u]==low[u])
{
size++;
int v;
do
{
v=s.top();
s.pop();
pos[v]=size;
val2[size]+=val1[v];
in[v]=false;
}while (v!=u);
}
}
void work_graph()
{
for (int u=1;u<=n;u++)
for (int i=old.head[u];i;i=old.pre[i])
{
int v=old.to[i];
if (pos[u]!=pos[v])
now.addedge(pos[v],pos[u]);
}
}
void mx(int u)
{
if (f[u]!=-inf) return ;
if (u==pos[S])
{
f[u]=val2[u];
return ;
}
for (int i=now.head[u];i;i=now.pre[i])
{
int v=now.to[i];
mx(v);
f[u]=max(f[u],f[v]+val2[u]);
}
}
void work()
{
S=read(),P=read();
for (int i=1;i<=size;i++) f[i]=-inf;
//注意用memset置的inf与实际的inf的大小是不一样的,
//这里的记忆化搜索需要判断是否来过(?==inf),就不能用memset,因为要保证一样
int ans=0;
for (int i=1;i<=P;i++)
{
int u=read();
mx(pos[u]);
ans=max(ans,f[pos[u]]);
}
printf("%d",ans);
}
int main()
{
init();//读入
for (int i=1;i<=n;i++) if (!dfn[i]) dfs(i);//求出强连通分量 ,注意必须有这个循环!!!
work_graph();//缩点
work();//记忆花搜索,求出这些点的路径最大权值
return 0;
}
总结
1:这题wa了好几次,原因是缩点,只从1开始dfs了,实际上,可能会有许许多多的块,应该再各个部分都dfs一下!!!!强连通分量必须加那个循环!!!
2:这道题写了,邻接表的结构体,感觉对于缩点的题更为方便。
3:注意memset出的inf和实际的inf是不一样的,所以如果需要判断是否等于inf,在初始赋值的时候不能用memset。