洛谷 題解 P3627 【[APIO2009]搶掠計劃】

圖論 tarjan縮點+最短路 的一道題

  • tarjan求強連通份量(爲之後縮點打下良好的基礎)

(若是不會tarjan的請點擊這兒)html

你須要的東西:
(1)、dfn[],表示這個點在dfs時是第幾個被搜到的。
(2)、low[],表示這個點以及其子孫節點連的全部點中dfn最小的值
(3)、stack[],表示當前全部可能能構成是強連通份量的點。
(4)、vis[],表示一個點是否在stack中。
(5)、color[],記錄每個點強連通份量的編號。
(6)、deep,記錄dfs樹的深度
inline void tarjan(int now)
{
    dfn[now]=++deep;
    low[now]=deep;
    vis[now]=1;
    st.push(now);
    for(int i=0;i<ver[now].size();i++)
    {
        int x=ver[now][i];
        if(!dfn[x])
        {
            tarjan(x);
            low[now]=min(low[now],low[x]);
        }
        else
        {
            if(vis[x])
                low[now]=min(low[now],low[x]);
        }
    }
    if(dfn[now]==low[now])
    {
        color[now]=++sum;
        vis[now]=0;
        while(st.top()!=now)
        {
            color[st.top()]=sum;
            vis[st.top()]=0;
            st.pop();
        }
        st.pop();
    }
}
  • 縮點(去除圖中的環)
//重點:這裏建新圖是依託強連通份量的編號來建的
for(int i=1;i<=n;i++)
    {
        for(int j=0;j<ver[i].size();j++)
        {
            int x=ver[i][j];
            if(color[i]!=color[x])//若是不是屬於同一個強連通份量中,那麼就合併
            {
                g[color[i]].push_back(color[x]);
           //千萬不能寫成g[i].push_back(x);坑死我了
            }
        }
    }
//這一部分代碼還能夠適當優化...(想想)
  • 對於點權與酒館的一些處理(方便求最短路)
for(int i=1;i<=n;i++)
    {
        ww[color[i]]+=w[i];//將這個強連通份量中全部的點權所有加起來
        if(tf[i])tf[color[i]]=1;//只要這個強連通份量中有一個結點有酒館,那麼就設定爲有酒館
    }
  • 求最短路模板(然而實際是最長路)
//模板不作解釋
inline void spfa()
{
    d[color[s]]=ww[color[s]];
    queue<int>q;
    q.push(color[s]);
    while(q.size())
    {
        int now=q.front();
        q.pop();
        for(int i=0;i<g[now].size();i++)
        {
            int x=g[now][i];
            if(d[now]+ww[x]>d[x])
            {
                d[x]=d[now]+ww[x];
                q.push(x);
            }
        }
    }
}

因此...c++

在全部有酒館的節點中選一個最大值輸出就行了優化

for(int i=1;i<=sum;i++)
    {
        //cout<<d[i]<<" ";
        if(tf[i])ans=max(ans,d[i]);
    }

完整代碼spa

#include<bits/stdc++.h>
using namespace std;
const int MAXN=500000+10;
int n,m;
vector<int>ver[MAXN];
vector<int>g[MAXN];
int w[MAXN],ww[MAXN];
bool tf[MAXN];
int s,p,ans=0;
int dfn[MAXN],color[MAXN],low[MAXN];
int deep,sum;
bool vis[MAXN];
int d[MAXN];
stack<int>st;
inline int read()
{
    int tot=0;
    char c=getchar();
    while(c<'0'||c>'9')
        c=getchar();
    while(c>='0'&&c<='9')
    {
        tot=tot*10+c-'0';
        c=getchar();
    }
    return tot;
}
inline void tarjan(int now)
{
    dfn[now]=++deep;
    low[now]=deep;
    vis[now]=1;
    st.push(now);
    for(int i=0;i<ver[now].size();i++)
    {
        int x=ver[now][i];
        if(!dfn[x])
        {
            tarjan(x);
            low[now]=min(low[now],low[x]);
        }
        else
        {
            if(vis[x])
                low[now]=min(low[now],low[x]);
        }
    }
    if(dfn[now]==low[now])
    {
        color[now]=++sum;
        vis[now]=0;
        while(st.top()!=now)
        {
            color[st.top()]=sum;
            vis[st.top()]=0;
            st.pop();
        }
        st.pop();
    }
}
inline void spfa()
{
    d[color[s]]=ww[color[s]];
    queue<int>q;
    q.push(color[s]);
    while(q.size())
    {
        int now=q.front();
        q.pop();
        for(int i=0;i<g[now].size();i++)
        {
            int x=g[now][i];
            if(d[now]+ww[x]>d[x])
            {
                d[x]=d[now]+ww[x];
                q.push(x);
            }
        }
    }
}
int main()
{
    //freopen("testdata.in","r",stdin);
    n=read();m=read();
    for(int i=1;i<=m;i++)
    {
        int x=read(),y=read();
        ver[x].push_back(y);
    }
    for(int i=1;i<=n;i++)
        w[i]=read();
    s=read();p=read();
    for(int i=1;i<=p;i++)
    {
        int x=read();
        tf[x]=1;
    }
    for(int i=1;i<=n;i++)
    {
        if(!dfn[i])
            tarjan(i);
    }
    /*cout<<endl;
    for(int i=1;i<=n;i++)
        cout<<color[i]<<" ";
    cout<<endl;*/
    for(int i=1;i<=n;i++)
    {
        for(int j=0;j<ver[i].size();j++)
        {
            int x=ver[i][j];
            if(color[i]!=color[x])
            {
                //cout<<i<<" "<<x<<" "<<color[i]<<" "<<color[x]<<endl;
                g[color[i]].push_back(color[x]);
            }
        }
    }
    for(int i=1;i<=n;i++)
    {
        ww[color[i]]+=w[i];
        if(tf[i])tf[color[i]]=1;
    }
    /*cout<<color[s]<<endl;
    cout<<endl;
    for(int i=1;i<=sum;i++)
    {
        for(int j=0;j<g[i].size();j++)cout<<i<<" "<<g[i][j]<<"\n";
    }
    cout<<endl;
    for(int i=1;i<=sum;i++)
        cout<<ww[i]<<" ";cout<<endl;
    for(int i=1;i<=sum;i++)
        cout<<tf[i]<<" ";cout<<endl;
    cout<<ww[color[s]]<<endl;*/
    spfa();
    for(int i=1;i<=sum;i++)
    {
        //cout<<d[i]<<" ";
        if(tf[i])ans=max(ans,d[i]);
    }
    //cout<<endl;
    cout<<ans<<endl;
    return 0;
}
相關文章
相關標籤/搜索