4 条题解

  • -2
    @ 2019-01-23 12:43:40

    //tarjan + DFS
    #include <iostream>
    #include <string>
    #include <queue>
    #include <stack>
    using namespace std;

    #define mmin(x, y) (x < y ? x : y)

    int ver[20010] = {0};
    int head[100010] = {0};
    int Next[20010] = {0};
    int ver2[20010] = {0};
    int head2[100010] = {0};
    int Next2[20010] = {0};

    int w[20010] = {0};
    int w2[20010] = {0};

    int dfn[100010] = {0};
    int low[100010] = {0};
    bool visited[100010];
    stack <int> s;
    int num = 0, cnt = 0;
    int color[100010] = {0};
    int color_num = 0;
    int maxx, sum;
    bool flag = false;

    void Add1(int u, int v) //初始构图
    {
    ++cnt;
    ver[cnt] = v;
    Next[cnt] = head[u];
    head[u] = cnt;
    }

    void Add2(int u, int v) //tarjan缩点后重新构图(有向无环图)
    {
    ++cnt;
    ver2[cnt] = v;
    Next2[cnt] = head2[u];
    head2[u] = cnt;
    }

    void tarjan(int u)
    {
    int i;
    low[u] = dfn[u] = ++num;
    visited[u] = true;
    s.push(u);
    for (i = head[u]; i; i = Next[i])
    {
    int v = ver[i];
    if (!dfn[v])
    {
    tarjan(v);
    low[u] = mmin(low[u], low[v]);
    }
    else if (visited[v])
    low[u] = mmin(low[u], dfn[v]);
    }

    if (dfn[u] == low[u])
    {
    ++color_num;
    color[u] = color_num;
    visited[u] = false;
    while (s.top() != u)
    {
    w[u] += w[s.top()];
    color[s.top()] = color_num;
    visited[s.top()] = false;
    s.pop();
    }
    w2[color_num] = w[u];
    s.pop();
    }
    }

    void DFS(int u)
    {
    int i;
    if (sum > maxx) maxx = sum;
    for (i = head2[u]; i; i = Next2[i])
    {
    sum += w2[ver2[i]];
    DFS(ver2[i]);
    sum -= w2[ver2[i]];
    }
    }

    int main()
    {
    int n, m, i, j, u, v;

    cin >> n >> m;
    for (i = 1; i <= n; ++i)
    cin >> w[i];
    for (i = 0; i < m; ++i)
    {
    cin >> u >> v;
    Add1(u, v);
    }

    for (i = 1; i <= n; ++i)
    visited[i] = false;

    for (i = 1; i <= n; ++i)
    if (!dfn[i])
    tarjan(i);

    //重新构图
    cnt = 0;
    for (i = 1; i <= n; ++i)
    {
    for (j = 1; j <= n; ++j)
    visited[j] = false;
    for (j = head[i]; j; j = Next[j])
    if (color[i] != color[ver[j]] && !visited[color[ver[j]]])
    {
    Add2(color[i], color[ver[j]]);
    visited[color[ver[j]]] = true;
    }
    }

    sum = w2[color[1]];
    maxx = 0;
    DFS(color[1]);

    cout << maxx << endl;

    return 0;
    }

  • -2
    @ 2019-01-22 20:09:23

    //别人的代码
    #include <cstdio>
    #include <vector>
    //#include <algorithm>
    #include <string>
    #include <stack>
    using namespace std;

    #define min(a, b) (a < b ? a : b)
    #define max(a, b) (a > b ? a : b)

    const int _ = 20001;
    int n, m, w[_];
    vector<int> e[_];
    stack<int> s;
    int cnt, dfn[_], low[_], vis[_], ins[_], r[_];

    void tarjan(int u) {
    vis[u] = ins[u] = 1;
    dfn[u] = low[u] = ++cnt;
    s.push(u);
    for (int i = 0; i < e[u].size(); ++i) {
    int &v = e[u][i];
    if (!vis[v]) {
    tarjan(v);
    low[u] = min(low[u], low[v]);
    }
    else if (ins[v]) {
    low[u] = min(low[u], dfn[v]);
    }

    }
    int sum = 0;
    if (dfn[u] == low[u]) {
    int t;
    do {
    t = s.top();
    s.pop();
    ins[t] = 0;
    sum += w[t];
    r[t] = u;
    }while(t != u);
    w[u] = sum;
    }
    }
    void upd() {
    for (int i = 1; i <= n; ++i) if (i != r[i]) {
    for (int j = 0; j < e[i].size(); ++j) {
    int &c = e[i][j];
    if (c != r[i]) e[r[i]].push_back(c);
    }
    }
    }
    int sum, ans;
    void dfs(int u) {
    sum += w[u];
    for (int i = 0; i < e[u].size(); ++i) {
    int &v = e[u][i];
    if (r[v] == u) continue;
    dfs(r[v]);
    }
    ans = max(ans, sum);
    sum -= w[u];
    }
    int main() {
    scanf("%d%d", &n, &m);
    for (int i = 1; i <= n; ++i) scanf("%d", w + i);
    while (m--) {
    int u, v;
    scanf("%d%d", &u, &v);
    e[u].push_back(v);
    }
    tarjan(1);
    upd();
    dfs(1);
    printf("%d", ans);
    return 0;
    }

  • -3
    @ 2019-01-23 14:15:13

    倘若是有向无环图,要求出奶牛能吃的最大草量,一种暴力的方法是使用深度优先搜索,另一种方法是使用拓扑排序,当前结点能吃的最大草量为该结点的最大的前驱结点的最大草量加上该结点的草量(原谅我垃圾的表述能力),即grass[i] = max{ grass[j] | j 是 i的前驱结点 } + w[i]。
    而本题并没有无环的限制,故无法直接使用拓扑排序求解。而在一个环即强连通分量中,奶牛不管怎么走,都可以吃到该环中的所有草,所以可以用tarjan算法将其缩成一个点,于是就可以得到一张有向无环图了。
    以下有三个题解,分别是深搜、拓扑排序以及,别人的代码(深搜)。希望大家可以看懂。。。

  • -3
    @ 2019-01-23 12:32:10

    //tarjan + toposort
    #include <iostream>
    #include <string>
    #include <queue>
    #include <stack>
    using namespace std;

    #define mmin(x, y) (x < y ? x : y)

    int ver[20010] = {0};
    int head[100010] = {0};
    int Next[20010] = {0};
    int ver2[20010] = {0};
    int head2[100010] = {0};
    int Next2[20010] = {0};

    int w[20010] = {0};
    int w2[20010] = {0};
    int maxx[20010] = {0};
    int root[20010] = {0};

    int dfn[100010] = {0};
    int low[100010] = {0};
    bool visited[100010];
    stack <int> s;
    int num = 0, cnt = 0;
    int color[100010] = {0};
    int color_num = 0;
    int max, sum;
    bool flag = false;

    void Add1(int u, int v) //初始构图
    {
    ++cnt;
    ver[cnt] = v;
    Next[cnt] = head[u];
    head[u] = cnt;
    }

    void Add2(int u, int v) //tarjan缩点后重新构图(有向无环图)
    {
    ++cnt;
    ver2[cnt] = v;
    Next2[cnt] = head2[u];
    head2[u] = cnt;
    }

    void tarjan(int u)
    {
    int i;
    low[u] = dfn[u] = ++num;
    visited[u] = true;
    s.push(u);
    for (i = head[u]; i; i = Next[i])
    {
    int v = ver[i];
    if (!dfn[v])
    {
    tarjan(v);
    low[u] = mmin(low[u], low[v]);
    }
    else if (visited[v])
    low[u] = mmin(low[u], dfn[v]);
    }

    if (dfn[u] == low[u])
    {
    ++color_num;
    color[u] = color_num;
    visited[u] = false;
    while (s.top() != u)
    {
    w[u] += w[s.top()];
    color[s.top()] = color_num;
    visited[s.top()] = false;
    s.pop();
    }
    w2[color_num] = w[u];
    s.pop();
    }
    }

    void toposort(int &n)
    {
    int du[110] = {0};
    int i, j;
    for (i = 1; i <= n; ++i)
    for (j = head2[i]; j; j = Next2[j])
    ++du[ver2[j]];

    queue <int> Q;
    for (i = 1; i <= n; ++i)
    if (!du[i]) Q.push(i);
    while (!Q.empty())
    {
    int u = Q.front();
    int edge = head2[u];
    w2[u] += maxx[u];
    Q.pop();
    while (edge)
    {
    --du[ver2[edge]];
    if (w2[u] > maxx[ver2[edge]] && root[u] == color[1]) //表示起点必须是1号结点
    {
    maxx[ver2[edge]] = w2[u];
    root[ver2[edge]] = root[u];
    }
    if (!du[ver2[edge]]) Q.push(ver2[edge]);
    edge = Next2[edge];
    }
    }
    }

    int main()
    {
    int n, m, i, j, u, v;

    cin >> n >> m;
    for (i = 1; i <= n; ++i)
    cin >> w[i];
    for (i = 0; i < m; ++i)
    {
    cin >> u >> v;
    Add1(u, v);
    }

    for (i = 1; i <= n; ++i)
    visited[i] = false;

    for (i = 1; i <= n; ++i)
    if (!dfn[i])
    tarjan(i);

    //重新构图
    cnt = 0;
    for (i = 1; i <= n; ++i)
    {
    for (j = 1; j <= n; ++j)
    visited[j] = false;
    for (j = head[i]; j; j = Next[j])
    if (color[i] != color[ver[j]] && !visited[color[ver[j]]])
    {
    Add2(color[i], color[ver[j]]);
    visited[color[ver[j]]] = true;
    }
    }

    root[color[1]] = color[1];
    toposort(color_num);

    int max = w2[color[1]];
    for (i = 1; i <= color_num; ++i)
    if (w2[i] > max && root[i] == color[1])
    max = w2[i];

    cout << max << endl;

    return 0;
    }

  • 1

奶牛吃草(这是一道附加题...)

信息

难度
7
分类
(无)
标签
(无)
递交数
70
已通过
15
通过率
21%
被复制
3
上传者