您的位置:首页 > 其它

洛谷2656 采蘑菇

2015-10-27 20:03 363 查看
洛谷2656 采蘑菇

本题地址: http://www.luogu.org/problem/show?pid=2656
题目描述

小胖和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算法求SCC+缩点。SCC中的结点是可以互相到达的因此SCC内部的边权可以全部获得,将每条指向SCC的边权加上SCC的内部边权,再求一遍最长路即可。

需要注意的有:

1、记录f而不要将w提前分解成边。

2、不要把大数组开在函数里面,否则会RE =-=。这点学了。

【代码】

#include<cstdio>
#include<cstring>
#include<queue>
#include<stack>
#include<cmath>
#include<iostream>
using namespace std;

const int maxn = 80000+10,maxm=200000+10;
const int INF=1<<30;
struct Edge{
int v,w,next;
double f;
}e[maxm];
int en=-1,front[maxn];

int n,m,s;

stack<int> S;
int scc_cnt,dfs_clock;
int sccno[maxn],pre[maxn],lowlink[maxn],scc_v[maxn];
void dfs(int u) {
pre[u]=lowlink[u]=++dfs_clock;
S.push(u);
for(int i=front[u];i>=0;i=e[i].next){
int v=e[i].v;
if(!pre[v]) {
dfs(v);
lowlink[u]=min(lowlink[u],lowlink[v]);
}
else if(!sccno[v]) {
lowlink[u]=min(lowlink[u],pre[v]);
}
}
if(lowlink[u]==pre[u])
{
scc_cnt++;
for(;;) {
int v=S.top(); S.pop();
sccno[v]=scc_cnt;
if(v==u) break;
}
}
}
void find_scc(int n) {
dfs_clock=scc_cnt=0;
memset(pre,0,sizeof(pre));
memset(sccno,0,sizeof(sccno));
for(int i=1;i<=n;i++)
if(!pre[i]) dfs(i);
}

inline void AddEdge(int u,int v,int w,double f) {
en++; e[en].v=v; e[en].w=w; e[en].f=f; e[en].next=front[u]; front[u]=en;
}

struct SPFA
{
Edge es[maxm];
int esn,fr[maxn];
int inq[maxn],d[maxn];
queue<int> q;
int n;
void init(int n) {
this->n=n; esn=0;
memset(fr,-1,sizeof(fr));
}
void addedge(int u,int v,int w) {
esn++; es[esn].v=v; es[esn].w=w; es[esn].next=fr[u]; fr[u]=esn;
}
void solve(int s) {
memset(inq,0,sizeof(inq));
for(int i=1;i<=n;i++) d[i]=-INF;

d[s]=scc_v[s]; inq[s]=1; q.push(s);
while(!q.empty()) {
int u=q.front(); q.pop(); inq[u]=0;
for(int i=fr[u];i>=0;i=es[i].next) {
int v=es[i].v,w=es[i].w;
if(d[v]<d[u]+w) {
d[v]=d[u]+w;
if(!inq[v]) {
inq[v]=1;
q.push(v);
}
}
}
}
int ans=0;
for(int i=1;i<=n;i++) ans=max(ans,d[i]);
printf("%d\n",ans);
}
};
SPFA spfa;

int main() {
memset(front,-1,sizeof(front));
scanf("%d%d",&n,&m);
int u,v,w; double f;
for(int i=0;i<m;i++) {
scanf("%d%d%d%lf",&u,&v,&w,&f);
AddEdge(u,v,w,f);
}
scanf("%d",&s);
find_scc(n);

spfa.init(scc_cnt);

for(int u=1;u<=n;u++) {
for(int i=front[u];i>=0;i=e[i].next) {
int v=e[i].v,w=e[i].w;
double f=e[i].f;
if(sccno[u]==sccno[v])
{
scc_v[sccno[v]] += w; w=(int)(w*f);
while(w) {
scc_v[sccno[v]] += w;
w=(int)(w*f);
}
}
}
}
for(int u=1;u<=n;u++) {
for(int i=front[u];i>=0;i=e[i].next) {
int v=e[i].v,w=e[i].w;
if(sccno[u]!=sccno[v]) {
w += scc_v[sccno[v]];    //sccno[v]
spfa.addedge(sccno[u],sccno[v],w);  //sccno[u]->sccno[v]
}
}
}

spfa.solve(sccno[s]);

return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: