| 网站首页 | 业界新闻 | 小组 | 威客 | 人才 | 下载频道 | 博客 | 代码贴 | 在线编程 | 编程论坛
欢迎加入我们,一同切磋技术
用户名:   
 
密 码:  
共有 6699 人关注过本帖
标题:写一个C程序
只看楼主 加入收藏
寒风中的细雨
Rank: 17Rank: 17Rank: 17Rank: 17Rank: 17
等 级:贵宾
威 望:66
帖 子:1710
专家分:8645
注 册:2009-9-15
收藏
得分:0 
程序代码:
第一个: 7   11   12   5   3   20   6   5   2     [71]
----------------------------------------------
第二个: 7   11   12   5 | 3   20   6   5   2     [35, 36]
----------------------------------------------
第三个: 7   11   12 | 5   3   20 | 6   5   2     [30, 28, 11]
----------------------------------------------
第四个: 7   11 | 12   5   3 | 20 | 6   5   2     [18, 20, 20, 13]
----------------------------------------------
第五个: 7   11 | 12 | 5   3 | 20 | 6   5   2     [18, 12, 8, 20, 13]
----------------------------------------------
第六个: 7 | 11 | 12 | 5   3 | 20 | 6   5   2     [7, 11, 12, 8, 20, 13]
----------------------------------------------
第七个: 7 | 11 | 12 | 5   3 | 20 | 6 | 5   2     [7, 11, 12, 8, 20, 6, 7]
----------------------------------------------
第八个: 7 | 11 | 12 | 5 | 3 | 20 | 6 | 5   2     [7, 11, 12, 5, 3, 20, 6, 7]
----------------------------------------------
第九个: 7 | 11 | 12 | 5 | 3 | 20 | 6 | 5 | 2     [7, 11, 12, 5, 3, 20, 6, 5, 2]
----------------------------------------------

1、选最大那个数列 进行拆分, 如果最大的数列中只含有一个数字那么选第二大的数列。。。以此类推, 直到可以找到能查分的最大数
2、选择完数列后然后进行拆分, 拆分(调整)后保证各部分拥有最小的最大值
2017-04-24 00:47
九转星河
Rank: 19Rank: 19Rank: 19Rank: 19Rank: 19Rank: 19
来 自:长长久久
等 级:贵宾
威 望:52
帖 子:5023
专家分:14003
注 册:2016-10-22
收藏
得分:0 
回复 32楼 寒风中的细雨
和31楼一并回复:31楼其实是用了逆向思维求解~这解法有点像用欧拉回路解决中国邮递员问题~但理解了实质还是和正向思维的方法上是一样的~

解决这题的关键是调整的方法~这题其实递推还是有点规律的~就是递推变动的各个指针都包含在原来划分的子区间里面的~也就是说如果之前划分区间的最优解里面只包含一个元素就没必要再变动这个区间了~反证得如果变动该区间能获取新的最优解那么之前划分的区间就不是最优解了~所以递推可以考虑依次在各个划分端点的后一个区间插入指针然后调整这样来捕获最优解~

[此贴子已经被作者于2017-4-24 04:01编辑过]


[code]/*~个性签名:bug是什么意思?bug是看上去没有可能的东西实际上是有可能做到的 就是这样~2018-08-08更~*/[/code]
2017-04-24 03:44
九转星河
Rank: 19Rank: 19Rank: 19Rank: 19Rank: 19Rank: 19
来 自:长长久久
等 级:贵宾
威 望:52
帖 子:5023
专家分:14003
注 册:2016-10-22
收藏
得分:0 
回复 32楼 寒风中的细雨
1 90| 40 40 10

感觉以和来划分最大子区间不太可靠~

就算 1 |90|40 40 10
这样来调整也要遍历才知道需要变动区间~但这样变动区间付出的代价是要向负方向搜索~所应感觉还是要每个子区间都要插入指针一次来调整捕获最优解~

不过如果是这样以和来划分就没啥意义了~所以感觉和只是代表一个价值取向趋势而不是必然成立的要素~如果是用和来划分存在不确定要素就意味着这个方法不能保证一定能得到最优解~

[此贴子已经被作者于2017-4-24 04:20编辑过]

收到的鲜花

[code]/*~个性签名:bug是什么意思?bug是看上去没有可能的东西实际上是有可能做到的 就是这样~2018-08-08更~*/[/code]
2017-04-24 03:58
寒风中的细雨
Rank: 17Rank: 17Rank: 17Rank: 17Rank: 17
等 级:贵宾
威 望:66
帖 子:1710
专家分:8645
注 册:2009-9-15
收藏
得分:0 
程序代码:
/**

 *\file test.cc

 */
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#include <math.h>
#include <string.h>

#define    MAX_ARY_SIZE    (100)    ///<

unsigned int g_val_ary[MAX_ARY_SIZE];

typedef struct res_st{
    
    unsigned int idx_beg;   ///< 起始下标
    unsigned int t_cnt;         ///< 数量包含的数字个数
    unsigned int t_val;        ///< 总的和
    unsigned int m_beg;        ///< 整个值 拆分成 最相近的 A,B 两个值,m_beg表示序列b的起始位置
    unsigned int A_val;
    unsigned int B_val;
}res_st;
res_st g_res[MAX_ARY_SIZE];

unsigned int g_res_cnt = 0;

/**

 *\brief 计算一个序列下次最佳拆分位置

 */
static void get_next_split_pos(res_st *pres)
{
    unsigned int i = 0, j = 0;
    
    if (pres->t_cnt == 1){
        
        return;
    }
    
    pres->A_val = pres->B_val = 0;
    for (i = 0, j = pres->t_cnt - 1; i <= j; ){
        
        if (pres->A_val > pres->B_val){
            
            pres->B_val += g_val_ary[pres->idx_beg + j];
            --j;
        }else{
            
            pres->A_val += g_val_ary[pres->idx_beg + i];
            ++i;
        }
    }
    
    pres->m_beg = pres->idx_beg + i;
}

/**

 *\brief 获取需要拆分的序列的下标值

 */
static unsigned int get_split_idx(void)
{
    unsigned int i, chg = 0, diff = 0, idx = 0;
    
    chg = 0;
    for (i = 0; i < g_res_cnt; ++i){
        
        if (g_res[i].t_cnt <= 1){
            
            continue;
        }
        diff = pow(g_res[i].t_val, 2.0) - pow(g_res[i].B_val, 2.0) - pow(g_res[i].A_val, 2.0);
        if (diff > chg){
            
            idx = i;
            chg = diff;
        }
    }
    
    return idx;
}

/**

 *\brief 进行指定的下标数字序列进行拆分

 */
static void deal_split(unsigned int idx)
{
    unsigned int i = 0, j = 0;
    
    /* 挪动一个位置 */
    for (i = g_res_cnt - 1; i > idx; --i){
        
        memcpy(&g_res[i + 1], &g_res[i], sizeof(res_st));
    }
    
    g_res[idx + 1].idx_beg = g_res[idx].m_beg;
    g_res[idx + 1].t_cnt = g_res[idx].t_cnt - (g_res[idx].m_beg - g_res[idx].idx_beg);
    g_res[idx + 1].t_val = g_res[idx].B_val;
    
    g_res[idx].t_cnt -= g_res[idx + 1].t_cnt;
    g_res[idx].t_val = g_res[idx].A_val;
    
    ++g_res_cnt;
}

/**

 *\brief 调整序列,使得相邻序列之间的差值最小

 */
static void adjust_seq(void)
{
    unsigned int i = 0, j = 0;
    unsigned int flag = 1;
    unsigned int sub1 = 0, sub2 = 0;
    
    while (flag){
        
        flag = 0;
        for (i = 0; i < g_res_cnt - 1; ++i){
            
            if (g_res[i].t_val > g_res[i + 1].t_val){
                    
                if (g_res[i].t_cnt == 1){
                    
                    continue;/* 一个不用调了 */
                }
                
                sub1 = g_res[i].t_val - g_res[i + 1].t_val;
                do{
                    sub2 = sub1;
                    j = g_res[i].idx_beg + g_res[i].t_cnt - 1;
                    sub1 = abs(g_res[i].t_val - g_res[i + 1].t_val - 2 * g_val_ary[j]);
                    if (sub1 < sub2){
                        
                        /* 调整 */
                        g_res[i].t_val -= g_val_ary[j];
                        g_res[i].t_cnt -= 1;
                        g_res[i+1].t_val += g_val_ary[j];
                        g_res[i+1].t_cnt += 1;
                        g_res[i+1].idx_beg -= 1;
                        flag = 1;
                    }else{
                        
                        break;
                    }
                }while (true);
            }else if (g_res[i].t_val < g_res[i + 1].t_val){

                if (g_res[i+1].t_cnt == 1){
                    
                    continue;/* 一个不用调了 */
                }
                
                sub1 = g_res[i+1].t_val - g_res[i].t_val;
                do{
                    sub2 = sub1;
                    j = g_res[i+1].idx_beg;
                    sub1 = abs(g_res[i+1].t_val - g_res[i].t_val - 2 * g_val_ary[j]);
                    if (sub1 < sub2){
                        
                        /* 调整 */
                        g_res[i].t_val += g_val_ary[j];
                        g_res[i].t_cnt += 1;
                        g_res[i+1].t_val -= g_val_ary[j];
                        g_res[i+1].t_cnt -= 1;
                        g_res[i+1].idx_beg += 1;
                        flag = 1;
                    }else{
                        
                        break;
                    }
                }while (true);    
            }
        }
    }
    
    for (i = 0; i < g_res_cnt; ++i){
        
        /* 计算最佳拆分位置 */
        get_next_split_pos(&g_res[i]);
    }
}

int main(void)
{
    unsigned int n = 0;
    unsigned int k = 0;
    unsigned int i = 0, j = 0;
    
    scanf("%u %u", &n, &k);
    assert(n >= k);
    
    /* 循环输入 */
    for (i = 0; i < n; ++i){
        
        scanf("%u", &g_val_ary[i]);
        g_res[g_res_cnt].t_val += g_val_ary[i];
    }
    g_res[g_res_cnt].idx_beg = 0;
    g_res[g_res_cnt].t_cnt = n;
    /* 计算最佳拆分位置 */
    get_next_split_pos(&g_res[g_res_cnt]);
    g_res_cnt = 1;
    
    while (g_res_cnt < k){
        
        /* 查找需要拆分的序列 */
        i = get_split_idx();
        
        /* 进行拆分 */
        deal_split(i);
        
        /* 调整各个序列 */
        adjust_seq();
    }
    
    /* 输出结果 */
    for (i = 0; i < g_res_cnt; ++i){
        
        for (j = 0; j < g_res[i].t_cnt; ++j){
            
            printf(" %u", g_val_ary[g_res[i].idx_beg + j]);
        }
        if (i + 1 < g_res_cnt){
            
            printf("|");
        }
    }
    printf("\n");
    
    return 0;
}


程序代码:
~/test # ./test
9 7
7 11 12 5 3 20 6 5 2

 7| 11| 12| 5 3| 20| 6| 5 2
~/test # ./test
4 2
6 2 2 6

 6 2| 2 6
~/test # ./test
5 3
100 1 1 1 1

 100| 1 1| 1 1

 ~/test # ./test
9 4
1 2 3 4 5 6 7 8 9

 1 2 3 4| 5 6| 7 8| 9

 ~/test # ./test
9 5
1 2 3 4 5 6 7 8 9

 1 2 3 4| 5 6| 7| 8| 9

 ~/test # ./test
5 3
5 7 11 4 21

 5 7| 11 4| 21

 ~/test # ./test
17 10
15 3 18 3 21 7 14 2 17 9 20 2 38 4 35 6 23

 15 3| 18 3| 21| 7 14| 2 17| 9| 20 2| 38| 4 35| 6 23

 ~/test # ./test
8 4
1 1 1 1 1 1 1 1

 1 1| 1 1| 1 1| 1 1

 ~/test # ./test
17 5
15 3 18 3 21 7 14 2 17 9 20 2 38 4 35 6 23

 15 3 18 3 21| 7 14 2 17 9| 20 2 38| 4 35| 6 23
2017-04-26 09:06
xzlxzlxzl
Rank: 15Rank: 15Rank: 15Rank: 15Rank: 15
来 自:湖北
等 级:贵宾
威 望:125
帖 子:1091
专家分:5825
注 册:2014-5-3
收藏
得分:0 
回复 34楼 寒风中的细雨
你这个显然也不是最优解,部分数据和我的对比如下:
我的分割:[15 3 18 3 |21 7 14 2 |17 9 20 2 |38 4 |35 6 23]=[N=17, K=5, Sum=11621]  我优,题主的结果是11605,不知道怎么分割的。

你的分割:[15 3 18 3 21| 7 14 2 17 9| 20 2 38| 4 35| 6 23]=[N=17, K=5, Sum=11963]
*****************************************************************************************************************************
我的分割:[15 3 |18 3 |21 |7 14 2 |17 9 |20 2 |38 |4 |35 |6 23]=[N=17, K=10, Sum=6421]

你的分割:[15 3| 18 3| 21| 7 14| 2 17| 9| 20 2| 38| 4 35| 6 23]=[N=17, K=10, Sum=6379] 你优

我是用不断调整平均数误差得到的结果,通过测试也只能部分数据和题主的结果完全对上,部分只能接近题主提供的测试结果。
目前我构思的一个算法估计要用递归穷尽的方法解决,有空时做下。
收到的鲜花
2017-04-27 06:42
ssr
Rank: 2
等 级:论坛游民
帖 子:33
专家分:11
注 册:2017-3-12
收藏
得分:0 
回复 35楼 xzlxzlxzl
5 3:5 7 11 4 21   //   810
5 3 : 1 2 3 4 5    //  77
8 4:  1 1 1 1 1 1 1 1    //   16

9 4       1293
9 5        1101
9 7        863
7 11 12 5 3 20 6 5 2

15 10     1177
15 13      957
1 2 3 4 5 6 7 8 9 10 11 12 11 10 8

10 3      15789
10 7       7523
4 38 14 14 15 20 32 13 46 21

10 7    10107
22 27 27 9 39 46 7 13 25 44

12 4        27294
12 7        15630
12 10      11566   
3 44  33 28 21 49 34 6 16 31 40 21

16 7:     9 36|18 29|38 4|24 20|13 17 21|24 15|23 21 14    //15420
16 11:   9 36|18|29|38|4 24|20|13 17|21|24|15 23|21 14   //10404

17 5:  15 3 18 3|21 7 14 2|17 9 20|2 38 4|35 6 23
17 10:   15 3|18 3|21|7 14|2 17|9|20 2|38|4 35|6 23
17 13:   15 3|18 3|21|7|14 2|17|9|20 2|38|4|35|6|23

18 4:  22 3 4 30 39|18 20 29 32|28 25 28 11 17|19 35 21 28     //41895
19 6:     27 47 24|23 32 10 29|3 33 48|48 20 22|11 19 49|21 45 16   //46561
20 15:   21|20|45|30|33|27|12 21|15 21|27|49|45|11 15|28 11|15 14|36   //17458

24 8:    27 31 9|23 37|7 7 18 32|4 8 32|41 8|11 22 22 5|21 32 7|11 33 13   //26971
24 13:  27|31|9 23|37|7 7 18|32 4|8 32|41|8 11 22|22 5 21|32|7 11|33 13   //17133
24 18:   27|31|9 23|37|7 7|18|32|4 8|32|41|8 11|22|22|5 21|32|7 11|33|13   //13087

[此贴子已经被作者于2017-4-27 08:41编辑过]

2017-04-27 08:07
寒风中的细雨
Rank: 17Rank: 17Rank: 17Rank: 17Rank: 17
等 级:贵宾
威 望:66
帖 子:1710
专家分:8645
注 册:2009-9-15
收藏
得分:0 
回复 35楼 xzlxzlxzl
程序代码:
/**

 *\brief 调整序列,使得相邻序列之间的差值最小

 */
static void adjust_seq(void)


看对比的数据,  这个调整序列的函数 需要做下改动,   在调整的时候 不仅是要比较相邻的两个序列, 应该是和剩余的所有序列进行对比, 然后调整。
2017-04-28 08:51
xzlxzlxzl
Rank: 15Rank: 15Rank: 15Rank: 15Rank: 15
来 自:湖北
等 级:贵宾
威 望:125
帖 子:1091
专家分:5825
注 册:2014-5-3
收藏
得分:0 
做递归时碰到问题未解决,为尽快得到结果,就根据递归算法衍生出“加法计算器算法”,已经完全能穷尽所有组合,得到的结果和题主给出的结果完全一样,效果及代码如下:

测试效果:
程序代码:
N=9, K=7
7 11 12 5 3 20 6 5 2 

 7 |11 |12 | 5  3 |20 | 6 | 5  2 --------Sum=863
N=9, K=5
7 11 12 5 3 20 6 5 2 

 7 11 |12 | 5  3 |20 | 6  5  2 --------Sum=1101
N=4, K=2
6 2 2 6 

 6  2 | 2  6 --------Sum=128
N=5, K=3
100 1 1 1 1 
100 | 1  1 | 1  1 --------Sum=10008
N=17, K=5
15 3 18 3 21 7 14 2 17 9 20 2 38 4 35 6 23 
15  3 18  3 |21  7 14  2 |17  9 20 | 2 38  4 |35  6 23 --------Sum=11605
N=17, K=10
15 3 18 3 21 7 14 2 17 9 20 2 38 4 35 6 23 
15  3 |18  3 |21 | 7 14 | 2 17 | 9 |20  2 |38 | 4 35 | 6 23 --------Sum=6379
N=17, K=13
15 3 18 3 21 7 14 2 17 9 20 2 38 4 35 6 23 
15  3 |18  3 |21 | 7 |14  2 |17 | 9 |20  2 |38 | 4 |35 | 6 |23 --------Sum=5615
N=18, K=4
22 3 4 30 39 18 20 29 32 28 25 28 11 17 19 35 21 28 
22  3  4 30 39 |18 20 29 32 |28 25 28 11 17 |19 35 21 28 --------Sum=41895
N=19, K=6
27 47 24 23 32 10 29 3 33 48 48 20 22 11 19 49 21 45 16 
27 47 24 |23 32 10 29 | 3 33 48 |48 20 22 |11 19 49 |21 45 16 --------Sum=46561
N=19, K=13
27 47 24 23 32 10 29 3 33 48 48 20 22 11 19 49 21 45 16 
27 |47 |24 23 |32 |10 29 | 3 33 |48 |48 |20 22 |11 19 |49 |21 |45 16 --------Sum=22823
N=24, K=8
27 31 9 23 37 7 7 18 32 4 8 32 41 8 11 22 22 5 21 32 7 11 33 13 
27 31  9 |23 37 | 7  7 18 32 | 4  8 32 |41  8 |11 22 22  5 |21 32  7 |11 33 13 --------Sum=26971
N=24, K=13
27 31 9 23 37 7 7 18 32 4 8 32 41 8 11 22 22 5 21 32 7 11 33 13 
27 |31 | 9 23 |37 | 7  7 18 |32  4 | 8 32 |41 | 8 11 22 |22  5 21 |32 | 7 11 |33 13 --------Sum=17133
N=24, K=18
27 31 9 23 37 7 7 18 32 4 8 32 41 8 11 22 22 5 21 32 7 11 33 13 
27 |31 | 9 23 |37 | 7  7 |18 |32 | 4  8 |32 |41 | 8 11 |22 |22 | 5 21 |32 | 7 11 |33 |13 --------Sum=13087


测试代码:
程序代码:
#include <stdio.h>
int setcount(int *a,int n,int k)
{//调整计数器,如果计数器内值不合法,则返回True
    int i,j;
    for(i=j=0;i<k;i++)
    {
        if(!a[i])a[i]=j+1;
        j=a[i];
    }
    for(i=0;i<k&&a[i]<=n;i++);
    return i<k;
}
int inccount(int *a,int n,int k)
{//计数器加1,并根据结果调整各位合法值,如果计数器第0位数据和数据位数的和大于总数据,则不合法,返回false
    int i,f=1;
    do
    {
        if(a[0]+k>n)return 0;
        for(i=k;i;i--)
        {
            a[i-1]+=f;
            f=0;
            if(a[i-1]>n)
            {
                a[i-1]=0;
                f=1;
            }
        }
        f=0;
    }while(setcount(a,n,k));
    return 1;
}
int sumsqu(int *a,int *b,int n,int k)
{//分段求平方和并返回
    int i,j,l,sum;
    for(i=j=l=sum=0;i<k-1;i++)
    {
        for(;j<b[i];j++)l+=a[j];
        sum+=l*l;
        l=0;
    }
    for(;j<n;j++)l+=a[j];
    sum+=l*l;
    return sum;
}
int main()
{
    int i,j,a[100],b[100],c[100],n,k;
    while(scanf("%d%d",&n,&k)&&n&&k)
    {
        for(i=0;i<n;i++)
        {
            b[i]=c[i]=0;
            scanf("%d",&a[i]);
        }
        setcount(b,n-1,k-1);
        while(inccount(b,n-1,k-1))
        {
            if(sumsqu(a,b,n,k)<sumsqu(a,c,n,k))
            {
                for(i=0;i<k;i++)c[i]=b[i];
            }
        }
        printf("N=%d, K=%d\n",n,k);
        for(i=0;i<n;i++)printf("%d ",a[i]);
        printf("\n");
        for(i=j=0;i<n;i++)
        {
            printf("%2d ",a[i]);
            if(i==c[j])
            {
                printf("|");
                j++;
            }
        }
        printf("--------Sum=%d\n",sumsqu(a,c,n,k));
    }
}
2017-04-28 18:50
九转星河
Rank: 19Rank: 19Rank: 19Rank: 19Rank: 19Rank: 19
来 自:长长久久
等 级:贵宾
威 望:52
帖 子:5023
专家分:14003
注 册:2016-10-22
收藏
得分:0 
回复 38楼 xzlxzlxzl
上楼应该是用穷举吧~感觉结果没错~不过输出数据有时会货不对板~例如

5 3
1 2 3 4 5
测试一下~~这个方法勉强能计到20位~

[code]/*~个性签名:bug是什么意思?bug是看上去没有可能的东西实际上是有可能做到的 就是这样~2018-08-08更~*/[/code]
2017-04-28 23:16
xzlxzlxzl
Rank: 15Rank: 15Rank: 15Rank: 15Rank: 15
来 自:湖北
等 级:贵宾
威 望:125
帖 子:1091
专家分:5825
注 册:2014-5-3
收藏
得分:0 
“不过输出数据有时会货不对板”是指什么?测试
5 3
1 2 3 4 5结果为“1 2 3|4|5---77”,没有问题啊!

我在38楼已明确说明了是穷举,位数多,效率肯定是问题。
其实,这题就是“动态规划”的题目,而动态规划是不一定得到最优解得。我的“动态调整平均数算法”在测试的数据里有一半的正确率,另一半和最优解很接近,我想是不是把这两个方法结合一下,缩小穷举的数据范围,或许可以大大提高获取最优解得效率呢?
2017-04-29 19:44
快速回复:写一个C程序
数据加载中...
 
   



关于我们 | 广告合作 | 编程中国 | 清除Cookies | TOP | 手机版

编程中国 版权所有,并保留所有权利。
Powered by Discuz, Processed in 0.026595 second(s), 9 queries.
Copyright©2004-2024, BCCN.NET, All Rights Reserved