[APIO 2009] Atm

传送门:>Here<

题意:给出一个有向图(有环),每个点有点权。从点S出发,经过每个点Tot可以加上点权,点可以经过多次,然而点权不能重复加多次。先要求走到某个终点E时点权最大。先要求在给定的某些终点E终,点权之和的最大值。

解题思路:

  题目有点难懂。首先如果只是暴力搜索的话,由于有环会无限循环,而且环内的值只会加一次,很容易想到强连通分量缩点。然后SPFA(改一改,变成最大值)求出每个点的最大值就可以了。然而如果某一个强连通分量里有酒吧,那么走到这个强联通分量作为终点一定是可以的。因此加个判断就好了。还是很水的……

Code

  Nothing

/*By QiXingzhi*/
#include <cstdio>
#include <queue>
#include <cstring>
#define  r  read()
#define  Max(a,b)  (((a)>(b)) ? (a) : (b))
#define  Min(a,b)  (((a)<(b)) ? (a) : (b))
typedef long long ll;
using namespace std;
const int MAXN = 500010;
const int MAXM = 1000010;
const int INF = 0x3f3f3f3f;
inline int read(){
    int x = 0; int w = 1; register int c = getchar();
    while(c ^ '-' && (c < '0' || c > '9')) c = getchar();
    if(c == '-') w = -1, c = getchar();
    while(c >= '0' && c <= '9') x = (x << 3) +(x << 1) + c - '0', c = getchar();
    return x * w;
}
bool bar[MAXN];
queue <int> q;
vector <int> G[MAXN],G2[MAXN];
int N,M,dfs_clock,S,P,scc_cnt,top,_x,ans;
int p[MAXN],sccno[MAXN],dfn[MAXN],low[MAXN],sta[MAXN],x[MAXN],y[MAXN],d[MAXN],val[MAXN],win[MAXN];
inline void AddEdge(int u, int v){ G[u].push_back(v); }
inline void AddEdge2(int u, int v){ G2[u].push_back(v); }
inline void tarjan(int u){
    dfn[u] = low[u] = ++dfs_clock;
    sta[++top] = u;
    int sz = G[u].size(), v;
    for(int i = 0; i < sz; ++i){
        v = G[u][i];
        if(!dfn[v]){ tarjan(v); low[u] = Min(low[u], low[v]); }
        else if(!sccno[v]) low[u] = Min(low[u], dfn[v]);
    }
    int X;
    if(dfn[u] == low[u]){
        ++scc_cnt;
        while(1){
            X = sta[top--];
            if(bar[X]) win[scc_cnt] = 1;
            sccno[X] = scc_cnt;
            val[scc_cnt] += p[X];
            if(X == u) break;
        }
    }
}
inline void BFS(int s){
    d[s] = val[s];
    q.push(s);
    int cur,sz,v;
    while(!q.empty()){
        cur = q.front(), q.pop();
        sz = G2[cur].size();
        for(int i = 0; i < sz; ++i){
            v = G2[cur][i];
            if(d[cur] + val[v] > d[v]){ d[v] = d[cur] + val[v]; q.push(v); }
        }
    }
}
int main(){
    N = r, M = r;
    for(int i = 1; i <= M; ++i){ x[i] = r, y[i] = r; AddEdge(x[i], y[i]); }
    for(int i = 1; i <= N; ++i) p[i] = r;
    S = r, P = r;
    for(int i = 1; i <= P; ++i) _x = r, bar[_x] = 1;
    for(int i = 1; i <= N; ++i) if(!dfn[i]) tarjan(i);
    for(int i = 1; i <= M; ++i) if(sccno[x[i]] != sccno[y[i]]) AddEdge2(sccno[x[i]], sccno[y[i]]);
    BFS(sccno[S]);
    for(int i = 1; i <= N; ++i) if(win[i]) ans = Max(ans, d[i]);
    printf("%d", ans);
    return 0;
}

转载于:https://www.cnblogs.com/qixingzhi/p/9353337.html

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值