[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;
}

 

posted @ 2019-08-14 21:44  委屈的咸鱼鱼鱼鱼  阅读(163)  评论(0编辑  收藏  举报