zoukankan      html  css  js  c++  java
  • 【tarjan+SPFA】BZOJ1179-[Apio2009]Atm

    【题目大意】

    给出一张有点权的有向图,已知起点和可以作为终点的一些点,问由起点出发,每条边和每个点可以经过任意多次,经过点的权值总和最大为多少。

    【思路】

    由于可以走任意多次,显然强连通分量可以缩点。然后就是一张DAG图,跑SPFA最长路就好了。

    听说Dijkstra写最长路会发生一些奇特的化学反应并且炸掉,还没想清楚姑且笔记一下。

      1 #include<bits/stdc++.h>
      2 using namespace std;
      3 const int MAXN=500000+50;
      4 struct edge
      5 {
      6     int to,len;
      7 };
      8 int n,m,s,p,money[MAXN],bar[MAXN],u[MAXN],v[MAXN];
      9 vector<int> E[MAXN];
     10 vector<edge> rE[MAXN];
     11 stack<int> S;
     12 queue<int> que;
     13 int instack[MAXN],low[MAXN],dfn[MAXN],sum[MAXN],col[MAXN],cnt,tot;
     14 int dis[MAXN],inque[MAXN];
     15 
     16 void addedge(int u,int v)
     17 {
     18     E[u].push_back(v);
     19 }
     20 
     21 void addedge2(int u,int v,int w)
     22 {
     23     rE[u].push_back((edge){v,w});
     24 }
     25 
     26 void tarjan(int x)
     27 {
     28     dfn[x]=low[x]=++cnt;
     29     instack[x]=1;
     30     S.push(x);
     31     for (int i=0;i<E[x].size();i++)
     32     {
     33         int to=E[x][i];
     34         if (!instack[to])
     35         {
     36             tarjan(to);
     37             low[x]=min(low[x],low[to]); 
     38         }
     39         else if (instack[to]==1)
     40         {
     41             low[x]=min(low[x],dfn[to]);
     42         }
     43     }
     44     
     45     if (dfn[x]==low[x])
     46     {
     47         tot++;
     48         int tmp;
     49         do
     50         {
     51             tmp=S.top();S.pop();
     52             sum[tot]+=money[tmp];
     53             col[tmp]=tot;
     54             instack[tmp]=2;
     55         }while (tmp!=x);
     56     }
     57 }
     58 
     59 void spfa(int start)
     60 {
     61     memset(inque,0,sizeof(inque));
     62     for (int i=1;i<=tot;i++) dis[i]=0;
     63     dis[start]=sum[start];
     64     inque[start]=1;
     65     que.push(start);
     66     while (!que.empty())
     67     {
     68         int head=que.front();que.pop();
     69         inque[head]=0;
     70         for (int i=0;i<rE[head].size();i++)
     71         {
     72             int to=rE[head][i].to,len=rE[head][i].len;
     73             if (dis[to]<dis[head]+len)
     74             {
     75                 dis[to]=dis[head]+len;
     76                 if (!inque[to])
     77                 {
     78                     inque[to]=1;
     79                     que.push(to);
     80                 }
     81             }
     82         }
     83     }
     84 }
     85 
     86 void rebuild()
     87 {
     88     for (int i=1;i<=m;i++)
     89         if (col[u[i]]!=col[v[i]]) addedge2(col[u[i]],col[v[i]],sum[col[v[i]]]);
     90 }
     91 
     92 void init()
     93 {
     94     scanf("%d%d",&n,&m);
     95     for (int i=1;i<=m;i++)
     96     {
     97         scanf("%d%d",&u[i],&v[i]);
     98         addedge(u[i],v[i]);
     99     }
    100     for (int i=1;i<=n;i++) scanf("%d",&money[i]);
    101     memset(bar,0,sizeof(bar));
    102     scanf("%d%d",&s,&p);
    103     for (int i=1;i<=p;i++)
    104     {
    105         int nowp;
    106         scanf("%d",&nowp);
    107         bar[nowp]=1;
    108     }
    109 } 
    110 
    111 void solve()
    112 {
    113     cnt=tot=0;
    114     memset(instack,0,sizeof(instack));
    115     for (int i=1;i<=n;i++)
    116         if (!instack[i]) tarjan(i);
    117     rebuild();
    118     spfa(col[s]);
    119     int ans=-1;
    120     for (int i=1;i<=n;i++)
    121         if (bar[i]) ans=max(ans,dis[col[i]]);
    122     printf("%d",ans);
    123 }
    124 
    125 int main()
    126 {
    127     init();
    128     solve();
    129     return 0;
    130 }
  • 相关阅读:
    175. 组合两个表
    101. 对称二叉树
    292. Nim游戏
    319. 灯泡开关
    155. 最小栈
    232. 用栈实现队列
    225. 用队列实现栈
    145. 二叉树的后序遍历
    144. 二叉树的前序遍历
    【leetcode】977. Squares of a Sorted Array
  • 原文地址:https://www.cnblogs.com/iiyiyi/p/6070493.html
Copyright © 2011-2022 走看看