挑战程序设计竞赛第二版里关于计数的dp里面的划分数讲解看不懂,求讲解

算球? 2016-08-11 03:48:13


在图里划红线的那个地方*****如果对于每个i都有ai > 0,那么{ai-1}就对应了n-m的m划分*****这里一直没看懂,,,,,看了别人写的解析也没看懂----http://www.hankcs.com/program/m-n-recursive-division.html---------求解答
...全文
218 6 打赏 收藏 转发到动态 举报
写回复
用AI写文章
6 条回复
切换为时间正序
请发表友善的回复…
发表回复
算球? 2016-08-15
  • 打赏
  • 举报
回复
谢谢楼上各位的解答
xskxzr 2016-08-12
  • 打赏
  • 举报
回复
引用 1 楼 xsklld 的回复:
比如4的1+2+1划分就对应1的0+1+0划分。
这里对应的意思是在集合 {n的所有不含0的m划分} 和集合 {n-m的所有m划分} 之间建立了一个双射(一一对应)。进而可以推导出这两个集合的大小相等。
赵4老师 2016-08-12
  • 打赏
  • 举报
回复
帮助弄懂DP请参考:
//http://www.cnblogs.com/chinazhangjie/archive/2010/11/16/1878400.html
//多边形游戏
//描述
//    一个多边形,开始有n个顶点。每个顶点被赋予一个正整数值,每条边被赋予一个运算符“+”或“*”。所有边依次用整数从1到n编号。
//    现在来玩一个游戏,该游戏共有n步:
//    第1步,选择一条边,将其删除
//    随后n-1步,每一步都按以下方式操作:
//    (1)选择一条边E以及由E连接着的2个顶点v1和v2;
//    (2)用一个新的顶点取代边E以及由E连接着的2个顶点v1和v2,将顶点v1和v2的整数值通过边E上的运算得到的结果值赋给新顶点。
//    最后,所有边都被删除,只剩一个顶点,游戏结束。游戏得分就是所剩顶点上的整数值。那么这个整数值最大为多少?
//输入
//    第一行为多边形的顶点数n(n ≤ 20),其后有n行,每行为一个整数和一个字符,
//    整数为顶点上的正整数值,字符为该顶点到下一个顶点间连边上的运算符“+”或“*”
//    (最后一个字符为最后一个顶点到第一个顶点间连边上的运算符)。
//输出
//    输出仅一个整数,即游戏所计算出的最大值。
//样例输入
//4
//4 *
//5 +
//5 +
//3 +
//样例输出
//70
//
//分析:
//最优子结构性质
//按照顺时针顺序,多边形和顶点的顺序可以写成:
//  op[1], v[1], op[2], v[2], …, op[n], v[n]
//在所给多边形中,从顶点i(1 <= i <= n)开始,长度为j(链中有j个顶点)的顺时针链p(i,j) 可表示为
//v[i], op[i+1], v[i+1],…, op[i+j-1], v[i+j-1]
//
//如果这条链在op[i + s]处进行最后一次合并运算(1 <= s <= j-1),则可在op[i+s]处将链分割为2个子链:
//
//从i开始长度为s的链:  p(i,s)
//从i + s开始,长度为j - s的链:p(i + s,j-s)。
//设:
//m1是对子链p(i,s)的任意一种合并方式得到的值,而a和b分别是在所有可能的合并中得到的最小值和最大值。
//
//m2是p(i+s,j-s)的任意一种合并方式得到的值,而c和d分别是在所有可能的合并中得到的最小值和最大值。
//
//依此定义有a <= m1 <= b,c <= m2 <= d
//
//(1)当op[i+s] = ‘+’时,显然有a + c <= m <= b + d
//
//(2)当op[i+s] = ’*’时,有
//
//min {ac,ad,bc,bd} <= m <= max {ac,ad,bc,bd}
//换句话说,主链的最大值和最小值可由子链的最大值和最小值得到。
#include <windows.h>
#include <stdio.h>
#include <string.h>
#include <conio.h>
#include <locale.h>
int n;
char o[21];//op
int  d[21];//vertex data
int maxv;
struct SEGINFO {//阶段信息
    int maxv;
    int minv;
} sg[21][21],si;
int X,Y;
void getXY() {
    CONSOLE_SCREEN_BUFFER_INFO csbi;
    GetConsoleScreenBufferInfo(GetStdHandle(STD_OUTPUT_HANDLE),&csbi);
    X=csbi.dwCursorPosition.X;
    Y=csbi.dwCursorPosition.Y;
}
void gotoXY(int x, int y) {
    COORD coord = {x, y};
    SetConsoleCursorPosition(GetStdHandle(STD_OUTPUT_HANDLE), coord);
}
void ConPrintAt(int x, int y, char *CharBuffer, int len) {
    DWORD count;
    COORD coord = {x, y};
    HANDLE hStdOut = GetStdHandle(STD_OUTPUT_HANDLE);
    SetConsoleCursorPosition(hStdOut, coord);
    WriteConsole(hStdOut, CharBuffer, len, &count, NULL);
}
void ClearCon() {
    HANDLE hStdOut = GetStdHandle(STD_OUTPUT_HANDLE);
    COORD coord = {0, 0};
    DWORD count;
    CONSOLE_SCREEN_BUFFER_INFO csbi;
    if (GetConsoleScreenBufferInfo(hStdOut, &csbi)) {
        FillConsoleOutputCharacter(hStdOut, (TCHAR) 32, csbi.dwSize.X * csbi.dwSize.Y, coord, &count);
        FillConsoleOutputAttribute(hStdOut, csbi.wAttributes, csbi.dwSize.X * csbi.dwSize.Y, coord, &count);
        SetConsoleCursorPosition(hStdOut, coord);
    }
}
void show(char *p) {
    int y,x;
    static char ss[128];

    for (y=1;y<n;y++) {
        sprintf(ss,"%c",o[y]);
        ConPrintAt(0,y,ss,1);
        for (x=1;x<n;x++) {
            sprintf(ss,"%2d ",sg[y][x].maxv);
            ConPrintAt(x*3,y,ss,3);
        }
    }
    sprintf(ss,"%-128s",p);
    ConPrintAt(1,n,ss,128);
    gotoXY(0,n);
}
void pmt(char *p) {
    static char ss[128];

    sprintf(ss,"%-128s",p);
    ConPrintAt(1,n,ss,128);
    gotoXY(0,n);
}
void getmaxmin(int i, int s, int j) {// 从i开始,长度为j,s为切分位置
    int minL;
    int maxL;
    int minR;
    int maxR;
    int r;
    int mm[4];
    int vmin;
    int vmax;
    static char p[128];

    minL=sg[i][s].minv;
    maxL=sg[i][s].maxv;         sprintf(p,"总长j:%d 上开始i:%d,长度  s:%d,maxL:%d",j,i,s  ,maxL);pmt(p);getXY();gotoXY(s    *3,i);getch();gotoXY(X,Y);


    r=(i+s-1)%(n-1)+1;
    minR=sg[r][j - s].minv;
    maxR=sg[r][j - s].maxv;     sprintf(p,"总长j:%d 下开始r:%d,长度j-s:%d,maxR:%d",j,r,j-s,maxR);pmt(p);getXY();gotoXY((j-s)*3,r);getch();gotoXY(X,Y);

    if (o[r] == '+') {// 处理加法
        si.minv=minL + minR;
        si.maxv=maxL + maxR;    sprintf(p,"上下合并maxv:%d=maxL:%d + maxR:%d",si.maxv,maxL,maxR);pmt(p);getch();
    } else {// 处理乘法
        mm[0]=minL * minR;
        mm[1]=minL * maxR;
        mm[2]=maxL * minR;
        mm[3]=maxL * maxR;
        vmin=mm[0];
        vmax=mm[0];
        for (i=1;i<4;i++) {
            if (mm[i]<vmin) vmin=mm[i];
            if (mm[i]>vmax) vmax=mm[i];
        }
        si.minv=vmin;
        si.maxv=vmax;           sprintf(p,"上下合并maxv:%d=maxL:%d * maxR:%d",si.maxv,maxL,maxR);pmt(p);getch();
    }
}
void pg() {
    int i,j,s;
    static char p[128];

    ClearCon();
    for (i=1;i<n;i++) {
        sg[i][1].maxv=d[i];
        sg[i][1].minv=d[i];
    }
    show("init");getch();
    for (j=2;j<n;j++) {//长度
        for (i=1;i<n;i++) {//起点
            for (s=1;s<j;s++) {//子切分位置
                getmaxmin(i,s,j);
                if (sg[i][j].minv > si.minv) sg[i][j].minv=si.minv;

                sprintf(p,"sg[开始i:%d][长度j:%d].maxv:%d < maxv=%d ?",i,j,sg[i][j].maxv,si.maxv);pmt(p);
                getXY();gotoXY(j*3,i);getch();gotoXY(X,Y);
                if (sg[i][j].maxv < si.maxv) {
                    sg[i][j].maxv=si.maxv;
                    show("");
                    sprintf(p,"Yes, sg[开始i:%d][长度j:%d].maxv:%d <-- maxv=%d",i,j,sg[i][j].maxv,si.maxv);pmt(p);
                    getXY();gotoXY(j*3,i);getch();gotoXY(X,Y);
                } else {
                    sprintf(p,"sg[开始i:%d][长度j:%d].maxv:%d < maxv=%d ? No",i,j,sg[i][j].maxv,si.maxv);pmt(p);
                    getch();
                }
            }
        }
    }
    sprintf(p,"规划完毕,下一步计算总maxv...");pmt(p);getch();
    maxv=sg[1][n-1].maxv;
    sprintf(p,"总maxv=sg[1][n-1].maxv:%d",maxv);pmt(p);
    getXY();gotoXY((n-1)*3,1);getch();gotoXY(X,Y);
    for (i=2;i<n;i++) {
        sprintf(p,"总maxv:%d < sg[开始i:%d][长度n-1:%d].maxv:%d ?",maxv,i,n-1,sg[i][n-1].maxv);pmt(p);
        getXY();gotoXY((n-1)*3,i);getch();gotoXY(X,Y);
        if (maxv < sg[i][n-1].maxv) {
            maxv=sg[i][n-1].maxv;
            sprintf(p,"Yes,总maxv:%d <-- sg[开始i:%d][长度n-1:%d].maxv:%d",maxv,i,n-1,sg[i][n-1].maxv);pmt(p);
            getXY();gotoXY((n-1)*3,i);getch();gotoXY(X,Y);
        } else {
            sprintf(p,"总maxv:%d < sg[开始i:%d][长度n-1:%d].maxv:%d ? No",maxv,i,n-1,sg[i][n-1].maxv);pmt(p);
            getch();
        }
    }
    sprintf(p,"计算出总maxv:%d",maxv);pmt(p);getch();
    gotoXY(0,n+1);
}

int main() {
    int i;
    char b[2];

    setlocale(LC_ALL,"chs");
    scanf("%d",&n);
    for (i=1;i<=n;i++) {
        scanf("%d%1s",&d[i],b);o[(i%n)+1]=b[0];
    }
    n++;
    pg();//PolyGame
    printf("%d\n",maxv);
    return 0;
}
//4
//1 +
//2 +
//4 +
//8 +
赵4老师 2016-08-12
  • 打赏
  • 举报
回复
仅供参考:
#include <stdio.h>
#include <stdlib.h>
void print(int res[], int num) {
    static int L=0;
    L++;
    printf("%8d:",L);
    for (int i=0;i<num;++i) {
        printf(" %d", res[i]);
    }
    printf("\n");
}
void split(int n, int m) {// n表示总数,m表示最大因子
    static int res[100];// 保存结果
    static int num=-1;// 当前因子下标

    if (n<m || n<0 || m<1) return;
    num++;
    if (0==n) {// 递归终止条件,为0不可再分,直接输出
        print(res,num+1);
        num--;
        return;
    } else {
        if (n==m) {// 不拆,直接输出
            res[num]=m;
            print(res,num+1);
            num--;
        } else {
            // 拆分出第一个
            res[num]=m;
            n=n-m;

            if (m>n) m = n; // 最大因子不可能大于总数

            for (int i=m;i>=1;--i) {// 循环,第二个因子可以继续拆分,而且按照最大因子不同可以拆分成多个
                split(n,i);
            }
            num--;
        }
    }
}
void Split(int n) {
    if (n<=0) return;
    if (100<n) {
        printf("Up to 100\n");
        return;
    }
    for (int i=n;i>=1;--i) {
        split(n, i);
    }
}
void main(int argc,char **argv) {
         if (argc<=1) Split(5);
    else if (argc>=3) split(atoi(argv[1]),atoi(argv[2]));
    else              Split(atoi(argv[1]));
}
“给定一个小点的输入,完整单步跟踪(同时按Alt+7键查看Call Stack里面从上到下列出的对应从里层到外层的函数调用历史)一遍。”是理解递归函数工作原理的不二法门! 递归函数关注以下几个因素 ·退出条件 ·参数有哪些 ·返回值是什么 ·局部变量有哪些 ·全局变量有哪些 ·何时输出 ·会不会导致堆栈溢出 http://www.codeproject.com/Articles/418776/How-to-replace-recursive-functions-using-stack-and
算球? 2016-08-12
  • 打赏
  • 举报
回复
引用 1 楼 xsklld 的回复:
比如4的1+2+1划分就对应1的0+1+0划分。
{ai}是一个集合,{ai-1}应该就是集合里的每个数字减1,,每个ai应该对应的是n的i划分吧,而你只是给了一个4的3划分的情况。我很懵逼啊
xskxzr 2016-08-11
  • 打赏
  • 举报
回复
比如4的1+2+1划分就对应1的0+1+0划分。

3,881

社区成员

发帖
与我相关
我的任务
社区描述
C/C++ 其它技术问题
社区管理员
  • 其它技术问题社区
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧