题目描述
小胖和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 80005
using 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;
}