zoukankan      html  css  js  c++  java
  • [USACO15JAN]草鉴定Grass Cownoisseur [tarjan spfa]

    P3119 [USACO15JAN]草鉴定Grass Cownoisseur

    先tarjan缩点 再分层建图 一层为逆向前 另一层为逆向走后 因为逆向只能走一次 所以上去了就下不来了

    会不会重复吃草场可以画一下图就能理解辽

    给定一个有向图G,有m张优惠券,可以把一条边的边权改成一个固定值k,求节点s到节点t之间最短路的长度和方案数。

    方法是建立一个m+1层的多层图,层与层之间的边的权值都为k,然后跑最短路。

    由于用了优惠券不一定能达到优化的目的,所以答案为min(t,t+n,t+n+n,...) 方案数也可如此做。

    还有一种解法 等我想来理解的时候再来搞叭

    #include<iostream>
    #include<cstdio>
    #include<queue>
    #include<cstring>
    #include<cmath>
    #include<stack>
    #include<algorithm>
    using namespace std;
    #define Max(x,y) ((x)>(y)?(x):(y))
    #define Min(x,y) ((x)<(y)?(x):(y))
    #define ll long long
    const int N=1e5+5,M=1e5+5,inf=0x3f3f3f3f,P=19650827;
    int n,m;
    template <class t>void rd(t &x){
        x=0;int w=0;char ch=0;
        while(!isdigit(ch)) w|=ch=='-',ch=getchar();
        while(isdigit(ch)) x=(x<<1)+(x<<3)+(ch^48),ch=getchar();
        x=w?-x:x;
    }
    
    int head[N],tot=0;
    struct edge{int u,v,nxt;}e[M],e2[M<<2];
    void add(int u,int v){
        e[++tot]=(edge){u,v,head[u]},head[u]=tot;
    }
    
    int idx=0,Bcnt=0,sz[N<<1],dfn[N],low[N],bl[N];
    bool inst[N];stack<int>s;
    void tarjan(int u){
        dfn[u]=low[u]=++idx;
        s.push(u),inst[u]=1;
        for(int i=head[u],v;i;i=e[i].nxt){
            v=e[i].v;
            if(!dfn[v]) tarjan(v),low[u]=Min(low[u],low[v]);
            else if(inst[v]&&dfn[v]<low[u]) low[u]=dfn[v];
        }
        if(dfn[u]==low[u]){
            int v;++Bcnt;
            do{
                v=s.top(),s.pop();
                bl[v]=Bcnt,inst[v]=0,++sz[Bcnt];
            }while(u!=v);
        }
    }
    
    int head2[N<<1],tot2=0;
    void add2(int u,int v){
        e2[++tot2]=(edge){u,v,head2[u]},head2[u]=tot2;
    }
    
    int dis[N<<1];
    bool vis[N<<1];queue<int>q;
    void spfa(int s){
        memset(vis,0,sizeof(vis));
        memset(dis,0,sizeof(dis));
        while(!q.empty()) q.pop();
        q.push(s),vis[s]=1;
        while(!q.empty()){
            int u=q.front();
            q.pop(),vis[u]=0;
            for(int i=head2[u],v;i;i=e2[i].nxt){
                v=e2[i].v;
                if(dis[v]<dis[u]+sz[v]){
                    dis[v]=dis[u]+sz[v];
                    if(!vis[v]) q.push(v),vis[v]=1;
                }
            }
        }
    }
    
    int main(){
        freopen("in.txt","r",stdin);
        rd(n),rd(m);
        for(int i=1,u,v;i<=m;++i) rd(u),rd(v),add(u,v);
        for(int i=1;i<=n;++i)
        if(!dfn[i]) tarjan(i);
        if(sz[bl[1]]==n) {printf("%d",n);return 0;}
        for(int i=1;i<=Bcnt;++i)
        sz[i+Bcnt]=sz[i];
        for(int i=1;i<=tot;++i)
        if(bl[e[i].u]!=bl[e[i].v]){
            add2(bl[e[i].u],bl[e[i].v]);
            add2(bl[e[i].v],bl[e[i].u]+Bcnt);
            add2(bl[e[i].u]+Bcnt,bl[e[i].v]+Bcnt);
        }
        spfa(bl[1]);
        printf("%d",dis[bl[1]+Bcnt]);
        return 0;
    }
  • 相关阅读:
    IPUtil
    MD5Util
    MyBatis环境配置及入门
    淘宝主页(静态页面)第3天
    淘宝主页(静态页面)第二天
    淘宝主页(静态页面)第1天
    力扣20 有效的括号
    力扣1 two sum
    JAVA可变参数
    JAVA环形队列
  • 原文地址:https://www.cnblogs.com/lxyyyy/p/11338857.html
Copyright © 2011-2022 走看看