[APIO2009-C]抢掠计划

题:https://www.cometoj.com/problem/0461

分析:求边双,最后求多汇点最长路

#include<iostream>
#include<cstring>
#include<algorithm>
#include<cstdio>
#include<vector>
#include<queue>
#define pb push_back
using namespace std;
const int M=5e5+5;
int sum[M],book[M],jiu[M],head[M],dfn[M],low[M],vis[M],sta[M],cmp[M],dis[M],val[M],newval[M],tot,top,cnt,num;
vector<int>g[M];
struct node{
    int v,w,nextt;
}e[M];
void tarjan(int u,int f){
    dfn[u]=low[u]=++cnt;
    sta[++top]=u;
    vis[u]=1;
    for(int i=0;i<g[u].size();i++){
        int v=g[u][i];
        if(v==f)
            continue;
        if(!dfn[v]){
            tarjan(v,u);
            low[u]=min(low[u],low[v]);
        }
        else if(vis[v])
            low[u]=min(low[u],dfn[v]);
    }
    if(low[u]==dfn[u]){
        cmp[u]=++tot;
        int countt=val[u];
        vis[u]=0;
        int len=top;
        while(sta[top]!=u){
            countt+=val[sta[top]];
            cmp[sta[top]]=tot;
            vis[sta[top--]]=0;
        }
        top--;
        sum[tot]=len-top;
        newval[tot]=countt;
    }
}
void addedge(int u,int v,int w){
    e[num].v=v;
    e[num].w=w;
    e[num].nextt=head[u];
    head[u]=num++;
}
int spfa(int s,int t){
    for(int i=s;i<=t;i++)
        dis[i]=0,vis[i]=0;
    queue<int>que;
    que.push(s);
    while(!que.empty()){
        int u=que.front();
        que.pop();
        vis[u]=0;
        for(int i=head[u];~i;i=e[i].nextt){
            int v=e[i].v;
            if(dis[v]<dis[u]+e[i].w){
                dis[v]=dis[u]+e[i].w;
                if(!vis[v])
                    vis[v]=1,que.push(v);

            }
        }
    }
    return dis[t];
}
int main(){
    int n,m;
    scanf("%d%d",&n,&m);
    for(int i=0;i<=n;i++)
        head[i]=-1;
    for(int i=1,u,v;i<=m;i++){
        scanf("%d%d",&u,&v);
        g[u].pb(v);
    }
    for(int i=1;i<=n;i++)
        scanf("%d",&val[i]);
    int s,p;
    scanf("%d%d",&s,&p);
    for(int i=1;i<=p;i++)
        scanf("%d",&jiu[i]);
    for(int i=1;i<=n;i++)
        if(!dfn[i])
            tarjan(i,-1);
    s=cmp[s];
    int t=tot+1;
    for(int i=1;i<=n;i++)
        for(int j=0,v;j<g[i].size();j++){
            v=g[i][j];
            if(cmp[i]!=cmp[v]){
    //m            cout<<cmp[i]<<"!!!!!"<<cmp[v]<<"!!!!"<<newval[cmp[i]]<<endl;
                addedge(cmp[i],cmp[v],newval[cmp[i]]);
            }
        }
    for(int i=1;i<=p;i++){
        if(book[cmp[jiu[i]]]==1)
            continue;
        book[cmp[jiu[i]]]=1;
        int w=newval[cmp[jiu[i]]];
    //    if(sum[cmp[jiu[i]]]>1)
    //        w=0;
    //        cout<<cmp[jiu[i]]<<"!!!!!"<<t<<"!!!!"<<w<<endl;
        addedge(cmp[jiu[i]],t,w);
    }
    printf("%d\n",spfa(s,t));
}

原文地址:https://www.cnblogs.com/starve/p/11614353.html

时间: 2024-10-11 12:14:28

[APIO2009-C]抢掠计划的相关文章

APIO2009 抢掠计划 Tarjan DAG-DP

APIO2009 抢掠计划 Tarjan DAG-DP 题面 一道\(Tarjan\)缩点水题.因为可以反复经过节点,所以把一个联通快中的所有路口看做一个整体,缩点后直接跑spfa或者dp就好了. 我选择了在DAG上跑dp,毕竟复杂度\(O(n)\) 拓扑时搞DP,\(f[i]\)表示在DAG上\(i\)节点时,当前最大钱数,转移\(f[v]=max(f[v], f[u]+w[v])?\) #include <cstdio> #include <queue> #define MAX

【p3627】[APIO2009] 抢掠计划

Description Siruseri 城中的道路都是单向的.不同的道路由路口连接.按照法律的规定, 在每个路口都设立了一个 Siruseri 银行的 ATM 取款机.令人奇怪的是,Siruseri 的酒吧也都设在路口,虽然并不是每个路口都设有酒吧. Banditji 计划实施 Siruseri 有史以来最惊天动地的 ATM 抢劫.他将从市中心 出发,沿着单向道路行驶,抢劫所有他途径的 ATM 机,最终他将在一个酒吧庆 祝他的胜利. 使用高超的黑客技术,他获知了每个 ATM 机中可以掠取的现金

[APIO2009]抢掠计划

题目描述 Siruseri 城中的道路都是单向的.不同的道路由路口连接.按照法律的规定, 在每个路口都设立了一个 Siruseri 银行的 ATM 取款机.令人奇怪的是,Siruseri 的酒吧也都设在路口,虽然并不是每个路口都设有酒吧. Banditji 计划实施 Siruseri 有史以来最惊天动地的 ATM 抢劫.他将从市中心 出发,沿着单向道路行驶,抢劫所有他途径的 ATM 机,最终他将在一个酒吧庆 祝他的胜利. 使用高超的黑客技术,他获知了每个 ATM 机中可以掠取的现金数额.他希 望

【bzoj1179】[Apio2009]抢掠计划atm 强连通分量缩点+spfa

Input 第一行包含两个整数N.M.N表示路口的个数,M表示道路条数.接下来M行,每行两个整数,这两个整数都在1到N之间,第i+1行的两个整数表示第i条道路的起点和终点的路口编号.接下来N行,每行一个整数,按顺序表示每个路口处的ATM机中的钱数.接下来一行包含两个整数S.P,S表示市中心的编号,也就是出发的路口.P表示酒吧数目.接下来的一行中有P个整数,表示P个有酒吧的路口的编号 Output 输出一个整数,表示Banditji从市中心开始到某个酒吧结束所能抢劫的最多的现金总数. Sample

洛谷3627 [APIO2009]抢掠计划

题目描述 输入格式: 第一行包含两个整数 N.M.N 表示路口的个数,M 表示道路条数.接下来 M 行,每行两个整数,这两个整数都在 1 到 N 之间,第 i+1 行的两个整数表示第 i 条道路的起点和终点的路口编号.接下来 N 行,每行一个整数,按顺序表示每 个路口处的 ATM 机中的钱数.接下来一行包含两个整数 S.P,S 表示市中心的 编号,也就是出发的路口.P 表示酒吧数目.接下来的一行中有 P 个整数,表示 P 个有酒吧的路口的编号. 输出格式: 输出一个整数,表示 Banditji

Tyvj1139 向远方奔跑(APIO 2009 抢掠计划)

描述 在唐山一中,吃饭是一件很令人头疼的事情,因为你不可能每次都站在队伍前面买饭,所以,你最需要做的一件事就是——跑饭.而跑饭的道路是无比艰难的,因为路是单向的(你要非说成是双向的我也没法,前提是你可以逆着2000+个狂热的跑饭群众而行),所以要合理选择路线.并且,在抵达你的目的地——板面馆之前,你需要先买一些干粮,比如烧饼之类的.现在给你每个干食商店的位置和干食喜爱度,请你设计一个跑饭方案使得在到达板面馆之前能得到尽可能多的干食喜爱度. 输入格式 第一行包含两个整数N.M.N表示食品商店的个数

BZOJ1179_APIO2009_抢掠计划_C++

题目:http://www.lydsy.com/JudgeOnline/problem.php?id=1179 一道用 Tarjan 缩点+SPFA 最长路的题(Tarjan 算法:http://www.cnblogs.com/hadilo/p/5889333.html ) 我们可以这样考虑,把一个连通块缩成一个点,点权为所有权值和,且只要一个点有酒吧那么该点也就有酒吧 因为当我们进入该连通块任意一个点时,显然把它里面所有的点都抢一遍才使答案最优,而且能回到原进入点,并且只要有一个有酒吧就可以选

抢掠计划

https://loj.ac/problem/10096 题目描述 某人准备从1号节点出发开始抢劫,并在一个有酒吧的节点停止抢劫,已知每个节点ATM机拥有的钱数,求最多抢劫的钱数(可重复经过道路,抢完后ATM机没钱). 思路 我们考虑对于一个强连通分量,他必定可以抢完这个强连通分量中所有的钱并到达任意节点,因此我们可以缩点.缩点之后每个点的点权即为这个强连通分量的总金额.我们对于缩点后的DAG,显然可以将点权转化为边权,在这张图上找最长路.这里最长路我们可以用spfa实现,这里我们避免用拓扑,因

【长沙集训】2017.9.12

并不怎么傻逼的题也把自己考成傻逼.大概是全机房最后几个改完题的人了..QAQ T1 APIO2009抢掠计划 好像是之前哪位学长讲过,tarjan缩点,然后值取反跑spfa或者拓扑排序后做Dp;考场上(第一次)尝试拓扑后DP,然后十分SB地一开始只放进了起点,认为其余入度为0的点无所谓(能过那么多点也是神奇).实际上显然需要把所有入读为0的点放入栈中,dp值初始为最大,起点为0,然后一边拓扑一边dp: //Twenty #include<cstdio> #include<cstdlib&