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。

 


 

發佈了331 篇原創文章 · 獲贊 17 · 訪問量 13萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章