洛谷P2656 采蘑菇

来源:互联网 发布:nginx根据不同url跳转 编辑:程序博客网 时间:2024/04/27 23:44

题目描述

小胖和ZYR要去ESQMS森林采蘑菇。

ESQMS森林间有N个小树丛,M条小径,每条小径都是单向的,连接两个小树丛,上面都有一定数量的蘑菇。小胖和ZYR经过某条小径一次,可以采走这条路上所有的蘑菇。由于ESQMS森林是一片神奇的沃土,所以一条路上的蘑菇被采过后,又会长出一些新的蘑菇,数量为原来蘑菇的数量乘上这条路的“恢复系数”,再下取整。

比如,一条路上有4个蘑菇,这条路的“恢复系数”为0.7,则第一~四次经过这条路径所能采到的蘑菇数量分别为4,2,1,0.

现在,小胖和ZYR从S号小树丛出发,求他们最多能采到多少蘑菇。

对于30%的数据,N<=7,M<=15

另有30%的数据,满足所有“恢复系数”为0

对于100%的数据,N<=80,000,M<=200,000,0.1<=恢复系数<=0.8且仅有一位小数,1<=S<=N.

输入输出格式

输入格式: 第一行,N和M

第2……M+1行,每行4个数字,分别表示一条小路的起点,终点,初始蘑菇数,恢复系数。

第M+2行,一个数字S

输出格式: 一个数字,表示最多能采到多少蘑菇,在int32范围内。

输入输出样例

输入样例#1:
3 3
1 2 4 0.5
1 3 7 0.1
2 3 4 0.6
1
输出样例#1:
8

这个题目用来练Tarjan真是太好不过了。刚上来我们就先进行缩点,缩完点后,重新建图,在建图的过程中处理出每个点的点权(缩出来的点如果原本是一个环,我们就不停地跑,每次都给他加上蘑菇数量*恢复系数,直到蘑菇数量为0,这样我们可以知道,这个强连通分量里面的能采到的所有蘑菇数,我们都赋给了这个新点的点权)。这样,我们再跑一边spfa,求一下最长路,这样就保证了我们采到的蘑菇尽量多。正确性显然。

代码如下:

#include<iostream>#include<cstdio>#include<cstdlib>#include<queue>using namespace std;const int maxn=80005;struct dqs{    int f,t,c;    double hui;}hh[maxn<<2];struct dqm{    int ff,tt,cc;}ha[maxn<<2];int first[maxn],next[maxn<<2];int tot=0;void build(int f,int t,int c,double hui){    hh[++tot]=(dqs){f,t,c,hui};    next[tot]=first[f];    first[f]=tot;}int lala=0;int fir[maxn],nxt[maxn<<2],d[maxn<<2];bool used[maxn];void add(int f,int t,int c){    ha[++lala]=(dqm){f,t,c};    nxt[lala]=fir[f];    fir[f]=lala;}int tot1=0,snum=0,cnt=0;int dfn[maxn],low[maxn],stack[maxn],jlqlt[maxn],size[maxn],dian[maxn];bool in_stack[maxn]; void group(int x){    dfn[x]=low[x]=++tot1;    stack[++snum]=x;    in_stack[x]=1;    for(int i=first[x];i;i=next[i])    {        int u=hh[i].t;        if(!dfn[u])        {            group(u);            low[x]=min(low[x],low[u]);        }        else if(in_stack[u])            low[x]=min(low[x],dfn[u]);    }    if(dfn[x]==low[x])    {        cnt++;        while(true)        {            jlqlt[stack[snum]]=cnt;            size[cnt]++;            in_stack[stack[snum]]=0;            snum--;            if(stack[snum+1]==x)            break;        }    }}queue<int>q;void spfa(int s){    d[s]=dian[s];    q.push(s);    used[s]=1;    while(!q.empty())    {        int x=q.front();        q.pop();        used[x]=0;        for(int i=fir[x];i;i=nxt[i])        {            int u=ha[i].tt;            if(d[u]<d[x]+ha[i].cc)            {                d[u]=d[x]+ha[i].cc+dian[u];                if(!used[u])                {                    used[u]=1;                    q.push(u);                }            }        }    }}int n,m,s;int main(){    scanf("%d%d",&n,&m);    for(int i=1;i<=m;i++)    {        int f,t,c;        double hui;        scanf("%d%d%d%lf",&f,&t,&c,&hui);        build(f,t,c,hui);    }    scanf("%d",&s);    for(int i=1;i<=n;i++)        if(!dfn[i])            group(i);    for(int i=1;i<=tot;i++)    {        int xx,yy;        xx=hh[i].f;        yy=hh[i].t;        if(jlqlt[xx]==jlqlt[yy])        {            int d=hh[i].c;            while(d)            {                dian[jlqlt[xx]]+=d;                d=d*hh[i].hui;            }        }        else            add(jlqlt[xx],jlqlt[yy],hh[i].c);    }    spfa(jlqlt[s]);    int ans=0;    for(int i=1;i<=cnt;i++)        ans=max(ans,d[i]);    printf("%d\n",ans);    return 0;}

神犇Loi_a打了拓扑排序,神的不得了啊,Orz。这里在征求他的同意下,也列出他的代码

#include<iostream>#include<cstdio>#include<queue>#include<stack>#include<cstring>#define maxn 80005using namespace std;struct E{    int to,nxt;    int d;double w; }b[300005];struct C{    int f,t,d;    double w;}cc[200005];int fst[maxn],tot;void build(int f,int t,int d,double w){b[++tot]=(E){t,fst[f],d,w};fst[f]=tot;}int dfs_c;int low[maxn],dfn[maxn];stack<int> S;int sccn[maxn],sz[maxn];int cnt;void dfs(int u){    dfn[u]=low[u]=++dfs_c;    S.push(u);    for(int i=fst[u];i;i=b[i].nxt)    {        int v=b[i].to;        if(!dfn[v])        {            dfs(v);            low[u]=min(low[u],low[v]);        }        else if(!sccn[v])            low[u]=min(low[u],dfn[v]);    }    if(low[u]==dfn[u])    {        cnt++;        while(true)        {            int v=S.top();            S.pop();            sccn[v]=cnt;            sz[cnt]++;            if(v==u) break;        }    }}int n,m,st;int val[maxn],dis[maxn];int rd[maxn];queue<int> q;void top(){    q.push(sccn[st]);    dis[sccn[st]]=val[sccn[st]];    while(!q.empty())    {        int u=q.front();        q.pop();        for(int i=fst[u];i;i=b[i].nxt)        {            int v=b[i].to;            rd[v]--;            dis[v]=max(dis[v],dis[u]+val[v]+b[i].d);            if(rd[v]==0) q.push(v);        }    }}int main(){    scanf("%d%d",&n,&m);    int s,t,v;double w;    for(int i=1;i<=m;i++)    {        scanf("%d%d%d%lf",&s,&t,&v,&w);        cc[i]=(C){s,t,v,w};        build(s,t,v,w);    }    scanf("%d",&st);    dfs(st);    memset(fst,0,sizeof(fst));    tot=0;    for(int i=1;i<=m;i++)    {        int f=cc[i].f,t=cc[i].t;        if(!sccn[f]) continue;        if(sccn[f]==sccn[t])        {            int d=cc[i].d;            while(d)            {                val[sccn[f]]+=d;                d*=cc[i].w;            }        }        else        {            build(sccn[f],sccn[t],cc[i].d,cc[i].w);            rd[sccn[t]]++;        }    }    top();    int ans=0;    for(int i=1;i<=cnt;i++)    {        ans=max(ans,dis[i]);    }    printf("%d",ans);    return 0;}