bzoj1179(缩点+乱搞)

 

很显然这道就是需要先求出强连通分量,然后缩点。缩点之后就是有向无环图了。实际上这之后,各种方法就都可以了。

已知的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。

 


 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值