zoukankan      html  css  js  c++  java
  • 1033 蚯蚓的游戏问题

    题目描述 Description

    在一块梯形田地上,一群蚯蚓在做收集食物游戏。蚯蚓们把梯形田地上的食物堆积整理如下:

                                                     a(1,1)  a(1,2)…a(1,m)

                                              a(2,1)  a(2,2)  a(2,3)…a(2,m)  a(2,m+1)     

                                         a(3,1)  a (3,2)  a(3,3)…a(3,m+1)  a(3,m+2)

                                 ……  

                                       a(n,1)   a(n,2)   a(n,3)…           a(n,m+n-1)     

           它们把食物分成n行,第1行有m堆的食物,每堆的食物量分别是a(1,1),a(1,2),…,a(1,m);

    第2行有m+1堆食物,每堆的食物量分别是a(2,1),a(2,2),…,  a(2,m+1);以下依次有m+2堆、m+3堆、…m+n-1堆食物。

    现在蚯蚓们选择了k条蚯蚓来测试它们的合作能力(1≤ k ≤m)。测试法如下:第1条蚯蚓从第1行选择一堆食物,然后往左下或右下爬,并收集1堆食物,例如从a(1,2)只能爬向a(2,2) 或a(2,3),而不能爬向其它地方。接下来再爬向下一行收集一堆食物,直到第n行收集一堆食物。第1条蚯蚓所收集到的食物量是它在每一行所收集的食物量之和;第2条蚯蚓也从第1行爬到第n行,每行收集一堆食物,爬的方法与第1条蚯蚓相类似,但不能碰到第1条蚯蚓所爬的轨迹;一般地,第i 条蚯蚓从第1行爬到第 n行,每行收集一堆食物,爬的方法与第1条蚯蚓类似,但不能碰到前 I-1 条蚯蚓所爬的轨迹。这k条蚯蚓应该如何合作,才能使它们所收集到的食物总量最多?收集到的食物总量可代表这k条蚯蚓的合作水平。

    • Ø编程任务:

           给定上述梯形m、n和k的值(1≤k≤m≤30;1≤n≤30)以及梯形中每堆食物的量(小于10的非整数),编程计算这k条蚯蚓所能收集到的食物的最多总量。

    输入描述 Input Description

           输入数据由文件名为INPUT1.*的文本文件提供,共有n+1行。每行的两个数据之间用一个空格隔开。

            ●第1行是n、m和k的值。

    • 接下来的n行依次是梯形的每一行的食物量a(i,1),a(i,2),…,a(i,m+i-1),i=1,2,…,n。
    输出描述 Output Description

    程序运行结束时,在屏幕上输出k蚯蚓条所能收集到的食物的最多总量。

    样例输入 Sample Input

    3    2   2    

    1   2

    5   0   2

    1   10  0  6

    样例输出 Sample Output

    26

    #include<iostream>
    #include<cstdio>
    #include<cmath>
    #include<cstring>
    #include<sstream>
    #include<algorithm>
    #include<queue>
    #include<deque>
    #include<iomanip>
    #include<vector>
    #include<cmath>
    #include<map>
    #include<stack>
    #include<set>
    #include<functional>
    #include<memory>
    #include<list>
    #include<string>
    using namespace std;
    typedef long long LL;
    typedef unsigned long long ULL;
    
    /*
    每个点只过一次 拆点建边(容量为1,费用为权值)
    k条蚯蚓,从源点流出容量为k
    源点向入点加边(容量为1,费用为0)
    出点向汇点加边(容量为1,费用为0)
    */
    const int MAXN = 10000;
    const int MAXM = 100000;
    const int INF = 0x3f3f3f3f;
    struct Edge
    {
        int to, next, cap, flow, cost;
    }edge[MAXM];
    int head[MAXN], tol;
    int pre[MAXN], dis[MAXN];
    bool vis[MAXN];
    int N;//节点总个数,节点编号从0~N-1
    void init(int n)
    {
        N = n;
        tol = 0;
        memset(head, -1, sizeof(head));
    }
    void addedge(int u, int v, int cap, int cost)
    {
        edge[tol].to = v;
        edge[tol].cap = cap;
        edge[tol].cost = cost;
        edge[tol].flow = 0;
        edge[tol].next = head[u];
        head[u] = tol++;
        edge[tol].to = u;
        edge[tol].cap = 0;
        edge[tol].cost = -cost;
        edge[tol].flow = 0;
        edge[tol].next = head[v];
        head[v] = tol++;
    }
    bool spfa(int s, int t)
    {
        queue<int>q;
        for (int i = 0; i < N; i++)
        {
            dis[i] = INF;
            vis[i] = false;
            pre[i] = -1;
        }
        dis[s] = 0;
        vis[s] = true;
        q.push(s);
        while (!q.empty())
        {
            int u = q.front();
            q.pop();
            vis[u] = false;
            for (int i = head[u]; i != -1; i = edge[i].next)
            {
                int v = edge[i].to;
                    if (edge[i].cap > edge[i].flow &&
                        dis[v] > dis[u] + edge[i].cost)
                    {
                        dis[v] = dis[u] + edge[i].cost;
                        pre[v] = i;
                        if (!vis[v])
                        {
                            vis[v] = true;
                            q.push(v);
                        }
                    }
            }
        }
        if (pre[t] == -1)return false;
        else return true;
    }
    //返回的是最大流,cost存的是最小费用
    int minCostMaxflow(int s, int t, int &cost)
    {
        int flow = 0;
        cost = 0;
        while (spfa(s, t))
        {
            int Min = INF;
            for (int i = pre[t]; i != -1; i = pre[edge[i ^ 1].to])
            {
                if (Min > edge[i].cap - edge[i].flow)
                    Min = edge[i].cap - edge[i].flow;
            }
            for (int i = pre[t]; i != -1; i = pre[edge[i ^ 1].to])
            {
                edge[i].flow += Min;
                edge[i ^ 1].flow -= Min;
                cost += edge[i].cost * Min;
            }
            flow += Min;
        }
        return flow;
    }
    int m, n, k;
    int val[MAXN];
    int Next[MAXN][2];
    int main()
    {
        ios::sync_with_stdio(0);
        cin >> n >> m >> k;
        int cnt = 1;
        for (int i = 0; i < n; i++)
        {
            for (int j = 0; j < m + i; j++)
            {
                if (i != n - 1)
                {
                    Next[cnt][0] = cnt + m + i;
                    Next[cnt][1] = Next[cnt][0] + 1;
                }
                cin >> val[cnt++];
            }
        }
        int num = cnt - 1;
        init(2 * num + 3);
        for (int i = 1; i <= cnt; i++)
        {
            addedge(i, i + num, 1, -val[i]);
            //cout << val[i] << endl;
        }
        for (int i = 1; i <= m; i++)
        {
            addedge(0, i, 1, 0);
            //cout << val[i] << endl;
        }
        for (int i = num, tmp = 1; tmp < m + n; i--, tmp++)
        {
            addedge(i + num, 2 * num + 1, 1, 0);
            //cout << val[i] << endl;
        }
        for (int i = 1; i <= cnt; i++)
        {
            if (Next[i][0] == 0 && Next[i][1] == 0) break;
            addedge(i + num, Next[i][0], 1, 0);
            addedge(i + num, Next[i][1], 1, 0);
        }
        addedge(2 * num + 2, 0, k, 0);
        int ans;
        minCostMaxflow(2 * num + 2, 2 * num + 1, ans);
        cout << -ans << endl;
        return 0;
    }
  • 相关阅读:
    在普通类中调用service
    layui util 工具时间戳转换
    最大值
    药房管理
    线段树2
    线段树1
    Dijkstra
    最大值最小化
    图的M 着色问题
    取余运算
  • 原文地址:https://www.cnblogs.com/joeylee97/p/7526544.html
Copyright © 2011-2022 走看看