您的位置:首页 > 其它

【洛谷 P2656】采蘑菇

2015-10-25 21:10 323 查看
好一次月赛,好一次良(bian)心(tai)的题目

我与靳小才那些不得不说的故事

因为有链接(懒得写),所以我就不上题面了~

这个题目,又是一道精彩的scc模(suan)板(fa)题

嗯,他们想尽可能多拿蘑菇,嗯

那一条边我能走几次走几次,有向图,想走几次走几次……?这是什么,告诉我——SCC!!!!

是的,就是SCC!

显然(其实没那么显然),scc上的边我可以尽可能的多拿走

just like

[code]int get_val(int i)
{
    int ret = l[i].v;
    int nowval = l[i].v;
    while(1)
    {
        nowval = nowval * l[i].c;
        if(!nowval) return ret;
        ret += nowval;
    }
}


其中,l是边,v是权值,c是那个double

好的,就是这样,我们把scc上的搞完了

那么其他的呢……?

且慢……

不不不不不不是DAG好烦啊,咱把它搞成个DAG吧

嗯,好主意

来吧

[code]    init();
    for(int i = 1;i <= m;i ++)
        if(scc_num[ff[i]] != scc_num[tt[i]])
            build(scc_num[ff[i]],scc_num[tt[i]],vv[i],cc[i]);


恩恩

ff是记录的

恩恩

所谓……遍历边……?

恩恩

就是这样

但是,缩点之前,我们不妨先求个scc中的ans

要不,叫点权好了

嗯,是个好主意

那么怎么办呢

val,dfs吧

dfs??

枚举



枚举

对对对

枚举多棒

就是dfs()?

好像是一样呀

本来就应该一样

不过庄周梦蝶罢了

也就是这样了:

[code]    for(int u = 1;u <= n;u ++)
        for(int i = first[u];~i;i = next[i])
            if(scc_num[u] == scc_num[l[i].t])
                val[scc_num[u]] += get_val(i);


然后,接下来是普通的言和 tarjan

[code]int dfs_clock,dfn[MAXN];
int scc_cnt,scc_num[MAXN];
int low[MAXN];
stack <int> s;
void dfs(int u)
{
    low[u] = dfn[u] = ++dfs_clock;
    s.push(u);
    for(int i = first[u];i != -1;i = next[i])
    {
        int v = l[i].t;
        if(!dfn[v])
        {
            dfs(v);
            low[u] = min(low[u],low[v]);
        }
        else if(!scc_num[v])
        {
            low[u] = min(low[u],dfn[v]);
        }
    }
    if(low[u] == dfn[u])
    {
        scc_cnt ++;
        while(true)
        {
            int x = s.top();
            s.pop();
            scc_num[x] = scc_cnt;
            if(x == u)
                break;
        }
    }
    return;
}


最后,跑个spfa什么的就好了

是最长路,最长路哦~~

[code]int use[MAXN],dis[MAXN];
deque <int> q;
void spfa(int S)
{
    memset(use,0,sizeof(use));
    memset(dis,0x80,sizeof(dis));
    dis[S] = val[S];
    use[S] = true;
    q.push_back(S);
    q.push_back(80001);
    while(!q.empty())
    {
        int u = q.front();
        q.pop_front();
        use[u] = false;
        for(int i = first[u];i != -1;i = next[i])
        {
            int v = l[i].t;
            if(dis[v] < dis[u] + l[i].v + val[v])
            {
                dis[v] = dis[u] + l[i].v + val[v];
                if(use[v])
                    continue;
                if(dis[v] > dis[q.front()])
                    q.push_front(v);
                else
                    q.push_back(v);
                use[v] = true;
            }
        }
    }
    return;
}


顺带一提,ans要这样处理

[code]    int ans = 0;
    for(int i = 1;i <= n;i ++)
        ans = max(ans,dis[i]);


总而言之,嘛

就是这样了

[code]#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <queue>
#include <stack>
using namespace std;
const int MAXN = 80000 + 5;
const int MAXM = 200000 + 5;
struct edge
{
    int f,t,v;
    double c;
}l[MAXM << 1];
int first[MAXN],next[MAXN << 1],tot;
void init()
{
    memset(first,0xfff,sizeof(first));
    tot = 0;
    return;
}
void build(int f,int t,int v,double c)
{
    l[++tot] = (edge){f,t,v,c};
    next[tot] = first[f];
    first[f] = tot;
    return;
}
int dfs_clock,dfn[MAXN];
int scc_cnt,scc_num[MAXN];
int low[MAXN];
stack <int> s;
void dfs(int u)
{
    low[u] = dfn[u] = ++dfs_clock;
    s.push(u);
    for(int i = first[u];i != -1;i = next[i])
    {
        int v = l[i].t;
        if(!dfn[v])
        {
            dfs(v);
            low[u] = min(low[u],low[v]);
        }
        else if(!scc_num[v])
        {
            low[u] = min(low[u],dfn[v]);
        }
    }
    if(low[u] == dfn[u])
    {
        scc_cnt ++;
        while(true)
        {
            int x = s.top();
            s.pop();
            scc_num[x] = scc_cnt;
            if(x == u)
                break;
        }
    }
    return;
}
int val[MAXN];
int get_val(int i)
{
    int ret = l[i].v;
    int nowval = l[i].v;
    while(1)
    {
        nowval = nowval * l[i].c;
        if(!nowval) return ret;
        ret += nowval;
    }
}
int use[MAXN],dis[MAXN];
deque <int> q;
void spfa(int S)
{
    memset(use,0,sizeof(use));
    memset(dis,0x80,sizeof(dis));
    dis[S] = val[S];
    use[S] = true;
    q.push_back(S);
    q.push_back(80001);
    while(!q.empty())
    {
        int u = q.front();
        q.pop_front();
        use[u] = false;
        for(int i = first[u];i != -1;i = next[i])
        {
            int v = l[i].t;
            if(dis[v] < dis[u] + l[i].v + val[v])
            {
                dis[v] = dis[u] + l[i].v + val[v];
                if(use[v])
                    continue;
                if(dis[v] > dis[q.front()])
                    q.push_front(v);
                else
                    q.push_back(v);
                use[v] = true;
            }
        }
    }
    return;
}
int n,m,S;
int ff[MAXM],tt[MAXM],vv[MAXM];
double cc[MAXM];
void solve()
{
    scanf("%d",&S);
    dfs(S);
        for(int u = 1;u <= n;u ++)
            for(int i = first[u];~i;i = next[i])
                if(scc_num[u] == scc_num[l[i].t])
                    val[scc_num[u]] += get_val(i);
    init();
    for(int i = 1;i <= m;i ++)
        if(scc_num[ff[i]] != scc_num[tt[i]])
            build(scc_num[ff[i]],scc_num[tt[i]],vv[i],cc[i]);
    spfa(scc_num[S]);
    int ans = 0;
    for(int i = 1;i <= n;i ++)
        ans = max(ans,dis[i]);
    printf("%d\n",ans);
    return;
}
int main()
{
    init();
    scanf("%d %d",&n,&m);
    for(int i = 1;i <= m;i ++)
    {
        scanf("%d %d %d %lf",&ff[i],&tt[i],&vv[i],&cc[i]);
        build(ff[i],tt[i],vv[i],cc[i]);
    }
    solve();
    return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: