codeforces 894E

来源:互联网 发布:淘宝官方活动报名入口 编辑:程序博客网 时间:2024/06/06 02:11

(强连通+dp)
题意:给定一个单向边的图(n,m<106),每条路上都有wi个宝石,每次经过一条路可将这条边上的宝石捡完,第i次经过该路,能捡到的宝石数量为wii(i+1)/2,直到宝石数目为0。 问从指定一点出发,最多能捡到多少宝石?

思路:由于每条路可以走很多遍,那么最好情况下是一直将每这条路重复走,直至该路上宝石被捡完。于是想到只有图中出现环可以这样,于是想到了tarjan缩点。缩点后,对于强连通内部的点来说,最关键的是想到:无论从哪一点出发,终点在哪里,在内部能捡到的宝石数目都是相同的,然后对于每个强连通计数即可;而对于强连通外部的DAG上,利用dp或者记忆化搜索的方式求解全局最优就好。

时间复杂度:缩点和计数的复杂度均为O(n+m)

#include <cstdio>#include <cmath>#include <algorithm>#include <cstring>#include <stack>#define LL long longusing namespace std;const int maxn = 1000050;const int inf = 0x3f3f3f3f;// basic structureint head[maxn], cnt;struct edge{    int to, next, w;}edge[maxn];void add_edge(int u, int v, int w) {    edge[cnt].to = v; edge[cnt].w = w;    edge[cnt].next = head[u]; head[u] = cnt ++;}// old_graphstack<int> s;int scc, dfs_clock;int DFN[maxn], low[maxn], blg[maxn]; //Depth First Number, low, belongbool instack[maxn]; //vis// new_graphLL dp[maxn], dis[maxn];int new_edge[maxn][3], new_cnt;void init_graph() {    cnt = 0;    memset(head, -1, sizeof(head));}void init_scc(int n) {    scc = dfs_clock = 0;    memset(DFN, -1, sizeof(DFN));    memset(instack, 0, sizeof(instack));    while(!s.empty()) s.pop();}void tarjan(int u) {    int v = 0;    DFN[u] = low[u] = dfs_clock ++;    s.push(u);    instack[u] = 1;    for(int k=head[u]; k!=-1; k=edge[k].next) {        v = edge[k].to;        if(DFN[v] == -1)            tarjan(v),low[u] = min(low[u],low[v]);        else if(instack[v])            low[u] = min(low[u],DFN[v]);    }    if(low[u] == DFN[u]) {        scc ++;        do {            v = s.top(); s.pop();            blg[v] = scc;            instack[v] = 0;        }        while(v != u);    }}void rebuild_graph(int n) {    new_cnt = 0;    for(int u=1; u<=n; u++) {        for(int k=head[u]; k!=-1; k=edge[k].next) {            int v = edge[k].to, w = edge[k].w;            if(blg[u] == blg[v]) {                int t = floor((-1+sqrt(1+8*w))/2); // n                dp[blg[u]] += (LL)(t+1)*w - (LL)t*(t+1)*(t+2)/6;            }            else {                new_edge[new_cnt][0] = blg[u], new_edge[new_cnt][1] = blg[v];                new_edge[new_cnt][2] = w; new_cnt ++;            }        }    }    init_graph();    for(int i=0; i<new_cnt; i++)        add_edge(new_edge[i][0], new_edge[i][1], new_edge[i][2]);}LL dfs(int u) {    if(dis[u] != -1) return dis[u];    LL ret = dp[u];    for(int k=head[u]; k!=-1; k=edge[k].next) {        int v = edge[k].to, w = edge[k].w;        ret = max(ret, dp[u] + (LL)w + dfs(v));    }    dis[u] = ret;    return ret;}int main() {    //freopen("test.txt","r",stdin);    int n, m, start;    scanf("%d%d",&n,&m);    init_graph();    init_scc(n);    while(m --) {        int u, v, w;        scanf("%d%d%d",&u,&v,&w);        add_edge(u, v, w);    }    scanf("%d",&start);    for(int i=1; i<=n; i++)        if(DFN[i] == -1) tarjan(i);    rebuild_graph(n);    for(int i=1; i<=scc; i++)        dis[i] = -1;    LL ans = dfs(blg[start]);    printf("%I64d\n",ans);    return 0;}
原创粉丝点击