ScubaDiv编程,输出逻辑错误

时间:2018-05-04 01:30:44

标签: c++ algorithm dynamic-programming

这个问题是关于一个潜水员或许多潜水员必须采取内部含有氧气和氮气的气瓶,气缸也有自己的重量。使用动态编程我们必须提出一个解决方案,告诉潜水员他们可以通过所需的Oxy和Nitro获得最佳重量(以最大化潜水员在水下的时间)

输入如下:

<div class="skiplinks">
		<a href="#wrapper">Skip to DIV</a>
		<a href="#anchor">Skip to ANCHOR</a>
	</div>
	
	<div id="wrapper">
		<p>Some boring content containing a selectable <a href="#">link</a>.</p>
		<ul id="nav">
			<li><a href="#">link 1</a></li>
			<li><a href="#">link 2</a></li>
			<li><a id="anchor" href="">anchor with href</a></li>
		</ul>
		<form id="search">
			<input type="search" id="search-field" />
		</form>
	</div>

此处的输出应如下所示:

1          //the number of divers
5 60       // ox=5 and ni=60 , the amonut of OX and NI the diver needs
5          //the number of cylinders to choose - n.
3 36 120   // 1st cyllinder => ox=3 / nit=36 / weight = 120
10 25 129  // 2nd cyllinder
5 50 250   // 3rd cyllinder
1 45 130   // 4th cyllinder
4 20 119   // 5th cyllinder

我可以找到249,所以重量但我很难理解如何获得cyllinders的索引,任何人都可以给我一个提示或指示我如何才能实现它。这是计算权重的函数:

249  //the tot weight
1 2  //cyllinders which were chosen (in this case 1st and 2nd cyllinder)

我尝试在第3个for循环中创建if语句:

int ox,ni,n;
int o[1000],nit[1000],w[1000];

int best[22][80],next[22][80];

int solve()
    {
        memset(best, 0x3f, sizeof(best));
        best[0][0] = 0;
        for (int k = 0; k < n ;k++)
        {
           memcpy(next,best,sizeof(best));

           for (int i = 0; i <= ox ;i++)
           {
                for (int j = 0 ; j <= ni ;j++)
                {
                    next[min(ox,i+o[k])][min(ni,j+nit[k])]= min(best[i][j]+w[k], next[min(ox,i+o[k])][min(ni,j+nit[k])]);
                }
           }
           memcpy(best,next,sizeof(best));
        }
        cout << endl;

        return best[ox][ni];
    }

但在大多数情况下都不起作用。任何人都可以给我一个提示或指导我如何使语句捕获并打印正确的柱面索引?

新的更新更改:

if (((next[min(ox,i+o[k])][min(ni,j+nit[k])]) == (best[i][j]+w[k])) && ((min(ox, i+o[k]) == ox) || (min(ni, j+nit[k])== ni) )) 
                    {
                        cout << k << " ";
                    }

1 个答案:

答案 0 :(得分:0)

我不确定您使用struct协调不同的坦克信息而不是尝试协调来自三个独立阵列的索引的建议取得了多大进展。这里有一些想法和一个例子。这个例子只是解决这个问题的众多方法之一,而且只是我在总结坦克信息以满足最低oxnit所需的时候,同时最大限度地减少总重量。

如果罐装重量替代品恰好提供相同的最小重量(这是您应该做的事情),则没有尝试最大化oxnit

首先,正如评论中所述,只要您需要在一个数据单元上协调多条信息,就需要考虑struct。在您的代码中,您尝试使用以下方式管理数据:

int ox,ni,n;
int o[1000],nit[1000],w[1000];

int best[22][80],next[22][80];

虽然可行但是,为一个应该“动态”处理数据的项目分配固定存储似乎从“Go”这个词来看是错误的(更不用说令人困惑)。相反,请使用简单的struct作为tank_type数据,例如

typedef struct {    /* typedef for struct containing tank vals */
    int ox,
        nit,
        wt;
} tank_t;

(您可以使用typedef来避免一直写stuct ...

好处是,您现在可以为no. of cylinders结构分配存储,然后使用单一协调索引访问您的数据,例如

    tank_t *tanks = NULL, ...;   /* pointer to tanks struct */
    ...
    /* validate number of cylinders read from file */
    if (fscanf (fp, "%d", &ncyl) != 1 || ncyl < 1) {
        fprintf (stderr, "error: read failed - no. of cylinders.\n");
        return 1;
    }
    ...
    /* allocate/validate storage for ncyl tanks */
    if ((tanks = calloc (ncyl, sizeof *tanks)) == NULL) {
        perror ("calloc-tanks");
        return 1;
    }

现在,您只需将数据读入tanks[0].ox, tanks[0].nit, ... tanks[1].ox, tanks[1].nit, ...

即可

要跟踪您的储罐索引,只需为no. of cylinders int分配,您可以将当前与1进行比较的索引设置为0。 (您可以使用类似的临时索引进行工作,并将符合条件的当前最小槽组合索引分配给将保存迭代结果的最终内存块)

问题的其余部分只是提出逻辑来迭代所有坦克组合,保存符合oxnit条件的每个组合的权重,并将每个组合与当前的最小值。您只需要确保在实现逻辑时,您正在跟踪的是根据需要重置值,以便最终进行有效比较。

(首先想到的是一个嵌套的循环集,类似于一个简单的数组排序例程,它将迭代并加在一起并比较各种组合。[毫无疑问,一种更有效的方法来实现它])

以下是结果,作为一种方法的示例(内联其他注释以帮助您跟进)。另请注意,我刚刚发布了您发布的数据文件(包括注释),因此如果您的实际文件省略了注释,您可以(略微)简化您的读取程序。

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <limits.h>

typedef struct {    /* typedef for struct containing tank vals */
    int ox,
        nit,
        wt;
} tank_t;

void empty_line (FILE *fp)  /* simple function to strip comments from */
{                           /* your input file */
    int c = fgetc (fp);

    while (c != '\n' && c != EOF)
        c = fgetc (fp);
}

int main (int argc, char **argv) {

    int ndivers = 0,        /* number of divers */
        oxreq = 0,          /* minimum oxygen required */
        nitreq = 0,         /* minimum nitrogen required */
        n = 0,              /* number of cylinders actually read */
        ncyl = 0,           /* number of cylinders from input file */
        wtmin = INT_MAX,    /* minimum weight (initialize to INT_MAX) */
        *indexes = NULL;    /* pointer to track tank indexes */
    tank_t *tanks = NULL, best = { .ox = 0 };   /* pointer to tanks struct */
    /* open file given as 1st argument or read from stdin */
    FILE *fp = argc > 1 ? fopen (argv[1], "r") : stdin;

    if (!fp) {  /* validate file open for reading */
        fprintf (stderr, "error: file open failed '%s'.\n", argv[1]);
        return 1;
    }

    /* validate number of divers read */
    if (fscanf (fp, "%d", &ndivers) != 1 || ndivers < 1) {
        fprintf (stderr, "error: read failed - number of divers.\n");
        return 1;
    }
    empty_line (fp);    /* strip remaining comments in line */

    /* validate required ox and nit read from file */
    if (fscanf (fp, "%d %d", &oxreq, &nitreq) != 2 || 
                oxreq < 1 || nitreq < 1) {
        fprintf (stderr, "error: read failed - ox, nit required.\n");
        return 1;
    }
    empty_line (fp);

    /* validate number of cylinders read from file */
    if (fscanf (fp, "%d", &ncyl) != 1 || ncyl < 1) {
        fprintf (stderr, "error: read failed - no. of cylinders.\n");
        return 1;
    }
    empty_line (fp);

    /* allocate/validate storage for ncyl integers */
    if ((indexes = calloc (ncyl, sizeof *indexes)) == NULL) {
        perror ("calloc-indexes");
        return 1;
    }

    /* allocate/validate storage for ncyl tanks */
    if ((tanks = calloc (ncyl, sizeof *tanks)) == NULL) {
        perror ("calloc-tanks");
        return 1;
    }

    /* read/validate tank information - store in tanks */
    while (n < ncyl && fscanf (fp, "%d %d %d", &tanks[n].ox, 
            &tanks[n].nit, &tanks[n].wt) == 3) {
        empty_line (fp);
        n++;
    }
    if (fp != stdin) fclose (fp);   /* close file if not stdin */

    /* loop over each tank to use as beginning in calc */
    for (int i = 0; i < n; i++) {
        int j = i + 1,      /* set 2nd index as next tank */
            *idx = calloc (n, sizeof *idx); /* allocate/zero temp index */
                            /* can move idx alloc out of loop & memset here */
        if (!idx) { /* validate allocation */
            perror ("calloc-idx");
            return 1;
        }
        /* use a temp tank_t struct tmp to accumulate values */
        tank_t tmp = { tanks[i].ox, tanks[i].nit, tanks[i].wt };
        idx[i] = 1;                     /* set 1st index value in tmp index */
        while (j < n) {                 /* loop over remaining tanks */
            idx[j] = 1;                 /* set next index as used */
            tmp.ox += tanks[j].ox;      /* add next tank ox */
            tmp.nit += tanks[j].nit;    /* add next tank nit */
            tmp.wt += tanks[j].wt;      /* add next tank wt */
            /* check if total ox & nit meet min, & wt < current min */
            if (tmp.ox > oxreq && tmp.nit > nitreq && tmp.wt < wtmin) {
                best = tmp;             /* save ox, nit & wt in best */
                wtmin = tmp.wt;         /* update minimum wt */
                memcpy (indexes, idx, n * sizeof *idx); /* copy to indexes */
                memset (idx, 0, sizeof *idx * n);   /* re-zero idx */
                memset (&tmp, 0, sizeof tmp);   /* zero tmp tank */
                idx[i] = 1;                     /* set 1st tank index */
                tmp.ox = tanks[i].ox;   /* set 1st tank values */
                tmp.nit = tanks[i].nit;
                tmp.wt = tanks[i].wt;
            }
            j++;    /* increment 2nd tank counter */
        }
        free (idx); /* free temp index */
    }
    free (tanks);   /* free tanks data - done with it */

    /* output results */
    printf ("best tank combo that meets: O2 >= %d, N >= %d\n\n"
            "  O2: %d\n  N : %d\n  wt: %d\n\n  tanks:",
            oxreq, nitreq, best.ox, best.nit, best.wt);
    for (int i = 0; i < n; i++)
        if (indexes[i])
            printf (" %d", i + 1);
    putchar ('\n');

    free (indexes); /* free final indexes */

    return 0;
}

示例输入文件

$ cat dat/tank.txt
1          //the number of divers
5 60       // ox=5 and ni=60 , the amonut of OX and NI the diver needs
5          //the number of cylinders to choose - n.
3 36 120   // 1st cyllinder => ox=3 / nit=36 / weight = 120
10 25 129  // 2nd cyllinder
5 50 250   // 3rd cyllinder
1 45 130   // 4th cyllinder
4 20 119   // 5th cyllinder

示例使用/输出

$ ./bin/tankopt <dat/tank.txt
best tank combo that meets: O2 >= 5, N >= 60

  O2: 13
  N : 61
  wt: 249

  tanks: 1 2

内存使用/错误检查

在你编写的动态分配内存的任何代码中,你有2个职责关于任何分配的内存块:(1)总是保留一个指向起始地址的指针内存块,(2)当不再需要时,它可以释放

必须使用内存错误检查程序,以确保您不会尝试访问内存或写入超出/超出已分配块的范围,尝试读取或基于未初始化值的条件跳转,最后,确认您释放了所有已分配的内存。

对于Linux valgrind是正常的选择。每个平台都有类似的记忆检查器。它们都很简单易用,只需通过它运行程序即可。

$ valgrind ./bin/tankopt <dat/tank.txt
==6126== Memcheck, a memory error detector
==6126== Copyright (C) 2002-2015, and GNU GPL'd, by Julian Seward et al.
==6126== Using Valgrind-3.12.0 and LibVEX; rerun with -h for copyright info
==6126== Command: ./bin/tankopt
==6126==
best tank combo that meets: O2 >= 5, N >= 60

  O2: 13
  N : 61
  wt: 249

  tanks: 1 2
==6126==
==6126== HEAP SUMMARY:
==6126==     in use at exit: 0 bytes in 0 blocks
==6126==   total heap usage: 7 allocs, 7 frees, 180 bytes allocated
==6126==
==6126== All heap blocks were freed -- no leaks are possible
==6126==
==6126== For counts of detected and suppressed errors, rerun with: -v
==6126== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)

始终确认已释放已分配的所有内存并且没有内存错误。

如果您还有其他问题,请与我们联系。如前所述,这个例子是为迭代和索引跟踪提供一种方法的例子 - 它不仅仅是为了做到这一点(或者是最有效的)

stdin

添加提示和阅读

如果您仔细注意,如果文件名作为第一个参数给出,则代码已设置为从文件中读取,如果没有参数, - 或 - stdin读取给出。这是通过在FILE声明中使用三元运算符来实现的,例如:

FILE *fp = argc > 1 ? fopen (argv[1], "r") : stdin;

三元运算符只是一个结构为if-else的简写(condition) ? value if true : value if false;。因此(argc > 1) ? fopen (argv[1], "r") : stdin;以上检查是argc > 1,如果是,则打开argv[i]中给出的文件名,否则只会将stdin分配给fp

知道你已经可以从stdin读取(并在上面的代码注释中提到的将idx的分配移动到循环之外),你可以执行以下操作来提示输入:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <limits.h>

typedef struct {    /* typedef for struct containing tank vals */
    int ox,
        nit,
        wt;
} tank_t;

void empty_line (FILE *fp)  /* simple function to strip comments from */
{                           /* your input file */
    int c = fgetc (fp);

    while (c != '\n' && c != EOF)
        c = fgetc (fp);
}

int main (int argc, char **argv) {

    int ndivers = 0,        /* number of divers */
        oxreq = 0,          /* minimum oxygen required */
        nitreq = 0,         /* minimum nitrogen required */
        n = 0,              /* number of cylinders actually read */
        ncyl = 0,           /* number of cylinders from input file */
        wtmin = INT_MAX,    /* minimum weight (initialize to INT_MAX) */
        *indexes = NULL,    /* pointer to track tank indexes */
        *idx = NULL;        /* pointer to temp index */
    tank_t *tanks = NULL, best = { .ox = 0 };   /* pointer to tanks struct */
    /* open file given as 1st argument or read from stdin */
    FILE *fp = argc > 1 ? fopen (argv[1], "r") : stdin;

    if (!fp) {  /* validate file open for reading */
        fprintf (stderr, "error: file open failed '%s'.\n", argv[1]);
        return 1;
    }

    if (fp == stdin)    /* prompt for no. of divers */
        fputs ("enter number of divers: ", stdout);

    /* validate number of divers read */
    if (fscanf (fp, "%d", &ndivers) != 1 || ndivers < 1) {
        fprintf (stderr, "error: read failed - number of divers.\n");
        return 1;
    }
    empty_line (fp);    /* strip remaining comments in line */

    if (fp == stdin)    /* prompt for no. of divers */
        fputs ("enter required oxygen and nitrogen: ", stdout);

    /* validate required ox and nit read from file */
    if (fscanf (fp, "%d %d", &oxreq, &nitreq) != 2 || 
                oxreq < 1 || nitreq < 1) {
        fprintf (stderr, "error: read failed - ox, nit required.\n");
        return 1;
    }
    empty_line (fp);

    if (fp == stdin)    /* prompt for no. of divers */
        fputs ("enter number of cylinders: ", stdout);

    /* validate number of cylinders read from file */
    if (fscanf (fp, "%d", &ncyl) != 1 || ncyl < 1) {
        fprintf (stderr, "error: read failed - no. of cylinders.\n");
        return 1;
    }
    empty_line (fp);

    /* allocate/validate storage for ncyl integers */
    if ((indexes = calloc (ncyl, sizeof *indexes)) == NULL) {
        perror ("calloc-indexes");
        return 1;
    }

    /* allocate/validate storage for ncyl tanks */
    if ((tanks = calloc (ncyl, sizeof *tanks)) == NULL) {
        perror ("calloc-tanks");
        return 1;
    }

    if (fp == stdin)    /* prompt for no. of divers */
        fprintf (stdout, "enter cylinder info (ox, nit, wt.) per-line:\n\n"
                "  enter info for cylinder[%2d]: ", n + 1);

    /* read/validate tank information - store in tanks */
    while (fscanf (fp, "%d %d %d", &tanks[n].ox, 
            &tanks[n].nit, &tanks[n].wt) == 3) {
        empty_line (fp);
        if (++n == ncyl)
            break;
        if (fp == stdin)    /* prompt for no. of divers */
            fprintf (stdout, "  enter info for cylinder[%2d]: ", n + 1);
        }
    if (fp != stdin) fclose (fp);   /* close file if not stdin */

    /* allocate/validate storage for temp indexes (idx) */
    if ((idx = calloc (n, sizeof *idx)) == NULL) {
        perror ("calloc-idx");
        return 1;
    }

    /* loop over each tank to use as beginning in calc */
    for (int i = 0; i < n; i++) {
        int j = i + 1;      /* set 2nd index as next tank */
        memset (idx, 0, sizeof *idx * n);   /* zero working index */
        /* use a temp tank_t struct tmp to accumulate values */
        tank_t tmp = { tanks[i].ox, tanks[i].nit, tanks[i].wt };
        idx[i] = 1;                     /* set 1st index value in tmp index */
        while (j < n) {                 /* loop over remaining tanks */
            idx[j] = 1;                 /* set next index as used */
            tmp.ox += tanks[j].ox;      /* add next tank ox */
            tmp.nit += tanks[j].nit;    /* add next tank nit */
            tmp.wt += tanks[j].wt;      /* add next tank wt */
            /* check if total ox & nit meet min, & wt < current min */
            if (tmp.ox > oxreq && tmp.nit > nitreq && tmp.wt < wtmin) {
                best = tmp;             /* save ox, nit & wt in best */
                wtmin = tmp.wt;         /* update minimum wt */
                memcpy (indexes, idx, n * sizeof *idx); /* copy to indexes */
                memset (idx, 0, sizeof *idx * n);   /* re-zero idx */
                memset (&tmp, 0, sizeof tmp);   /* zero tmp tank */
                idx[i] = 1;                     /* set 1st tank index */
                tmp.ox = tanks[i].ox;   /* set 1st tank values */
                tmp.nit = tanks[i].nit;
                tmp.wt = tanks[i].wt;
            }
            j++;    /* increment 2nd tank counter */
        }
    }
    free (idx); /* free temp index */
    free (tanks);   /* free tanks data - done with it */

    /* output results */
    printf ("\nbest tank combo that meets: O2 >= %d, N >= %d\n\n"
            "  O2: %d\n  N : %d\n  wt: %d\n\n  tanks:",
            oxreq, nitreq, best.ox, best.nit, best.wt);
    for (int i = 0; i < n; i++)
        if (indexes[i])
            printf (" %d", i + 1);
    putchar ('\n');

    free (indexes); /* free final indexes */

    return 0;
}

示例使用/输出(从stdin w /提示读取)

$ ./bin/tankopt2
enter number of divers: 1
enter required oxygen and nitrogen: 5 60
enter number of cylinders: 5
enter cylinder info (ox, nit, wt.) per-line:

  enter info for cylinder[ 1]: 3 36 120
  enter info for cylinder[ 2]: 10 25 129
  enter info for cylinder[ 3]: 5 50 250
  enter info for cylinder[ 4]: 1 45 130
  enter info for cylinder[ 5]: 4 20 119

best tank combo that meets: O2 >= 5, N >= 60

  O2: 13
  N : 61
  wt: 249

  tanks: 1 2