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;
}
时间: 2024-11-02 02:09:14

1033 蚯蚓的游戏问题的相关文章

【CODEVS】1033 蚯蚓的游戏问题

[算法]网络流-最小费用最大流(费用流) [题解]与方格取数2类似 在S后添加辅助点S_,限流k 每条边不能重复走,限流1 #include<cstdio> #include<algorithm> #include<cstring> using namespace std; const int inf=0x3f3f3f3f,maxn=40,maxN=5000; struct edge{int from,v,flow,cost;}e[150000]; int n,m,k,

codevs1033 蚯蚓的游戏问题

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

【codevs1033】 蚯蚓的游戏问题

http://codevs.cn/problem/1033/ (题目链接) 题意 给出一个梯形的数列,每一个数可以向它左下方和右下方的数走.求从第一行走到最后一行的不重叠的K条路径,使得经过的数的和最大. Solution 很显然的费用流.每个点拆成两个,之间连一条容量为1,费用为数字大小的边. 细节 最近写题总是bug百出..网络流的数组大小真是玄学问题.. 代码 // codevs1033 #include<algorithm> #include<iostream> #incl

Codevs1033蚯蚓的游戏问题-费用流

将田地上的食物取负,求图的最小费用流即为最大费用流的相反数.(ps第一次听说还可以这样用思路:用spfa求最短路,沿着最短路增广. 1 #include<iostream> 2 #include<algorithm> 3 #include<cstdlib> 4 #include<cstdio> 5 #include<vector> 6 #include<queue> 7 #define maxn 0x3f3f3f3f 8 using

7、8月刷题总结

准备开学了囧,7.8月刷题记录,以后好来复习,并且还要好好总结! 数据结构: splay: [BZOJ]1503: [NOI2004]郁闷的出纳员(Splay) [BZOJ]1269: [AHOI2006]文本编辑器editor(Splay) [BZOJ]1507: [NOI2003]Editor(Splay) treap: [BZOJ]1862: [Zjoi2006]GameZ游戏排名系统 & 1056: [HAOI2008]排名系统(treap+非常小心) [BZOJ]3224: Tyvj

大神刷题表

9月27日 后缀数组:[wikioi3160]最长公共子串 dp:NOIP2001统计单词个数 后缀自动机:[spoj1812]Longest Common Substring II [wikioi3160]最长公共子串 [spoj7258]Lexicographical Substring Search 扫描线+set:[poj2932]Coneology 扫描线+set+树上删边游戏:[FJOI2013]圆形游戏 结论:[bzoj3706][FJ2014集训]反色刷 最小环:[poj1734

【BZOJ 1033】 [ZJOI2008]杀蚂蚁antbuster

1033: [ZJOI2008]杀蚂蚁antbuster Time Limit: 10 Sec  Memory Limit: 128 MB Submit: 583  Solved: 230 [Submit][Status] Description 最近,佳佳迷上了一款好玩的小游戏:antbuster.游戏规则非常简单:在一张地图上,左上角是蚂蚁窝,右下角是蛋糕,蚂蚁会源源不断地从窝里爬出来,试图把蛋糕搬回蚂蚁窝.而你的任务,就是用原始资金以及杀蚂蚁获得的奖金造防御塔,杀掉这些试图跟你抢蛋糕的蚂蚁

BZOJ 1033 杀蚂蚁

Description 最近,佳佳迷上了一款好玩的小游戏:antbuster.游戏规则非常简单:在一张地图上,左上角是蚂蚁窝,右下角是蛋糕,蚂蚁会源源不断地从窝里爬出来,试图把蛋糕搬回蚂蚁窝.而你的任务,就是用原始资金以及杀蚂蚁获得的奖金造防御塔,杀掉这些试图跟你抢蛋糕的蚂蚁~ 下附一张游戏截图: 为了拿到尽可能高的分数,佳佳设计了很多种造塔的方案,但在尝试了其中的一小部分后,佳佳发现,这个游戏实在是太费时间了.为了节省时间,佳佳决定写个程序,对于每一种方案,模拟游戏进程,根据效果来判断方案的优

Python:游戏:贪吃蛇(附源码)

贪吃蛇是个非常简单的游戏,适合练手. 首先分析一下这个游戏 1.蛇怎么画? 蛇是由一个个小方块组成的,那么我们可以用一个 list 记录每一个小方块的坐标,显示的时候将所有小方块画出来即可. 2.蛇怎么移动? 第一反应就是想蚯蚓蠕动一样,每一个方块向前移动一格,但这样做很麻烦,仔细想下,其实除了头尾,蛇的其他部分根本就没有动过,那就简单了,将下一格的坐标添加到 list 开头,并移除 list 的最后一个元素,就相当于蛇向前移动了一格. 3.如何判定游戏结束? 蛇移动超出了游戏区的范围或者碰到了