| 网站首页 | 业界新闻 | 小组 | 威客 | 人才 | 下载频道 | 博客 | 代码贴 | 在线编程 | 编程论坛
欢迎加入我们,一同切磋技术
用户名:   
 
密 码:  
共有 5430 人关注过本帖
标题:一个关于方阵数组取值问题~
只看楼主 加入收藏
NiuYoohoo
Rank: 4
等 级:业余侠客
威 望:2
帖 子:65
专家分:216
注 册:2016-10-8
收藏
得分:3 
深度遍历 或者 优先级排序
2017-04-18 10:22
yangfrancis
Rank: 16Rank: 16Rank: 16Rank: 16
等 级:贵宾
威 望:141
帖 子:1510
专家分:7661
注 册:2014-5-19
收藏
得分:10 
#include<iostream>
#include<vector>
using namespace std;
struct MatrixElem
{
    unsigned int n;
    unsigned int x_ordinate;//将用于保存二维MatrixElem数组中本元素自身的下标
    unsigned int y_ordinate;//将用于保存二维MatrixElem数组中本元素自身的下标
    bool operator==(const MatrixElem& righthand)
    //定义等号,新元素进入向量时用find函数检查是否已有横或纵坐标一样的元素
    {
        return x_ordinate==righthand.x_ordinate||y_ordinate==righthand.y_ordinate;
    }
    MatrixElem operator+(const MatrixElem& righthand)//定义加号,好算元素之和
    {
        MatrixElem result={n+righthand.n,0,0};//坐标不用管,用不着的
        return result;
    }
};
template<typename T>
class MyVector:public vector<T>
{
public:
    bool find(T d)//定义一个在向量中查找指定元素的函数
    {
        iterator itr;
        for(itr=begin();itr!=end();itr++)
            if(*itr==d)return true;
        return false;
    };
    T sum()
    {
        iterator itr;T t={0,0,0};
        for(itr=begin();itr!=end();itr++)
            t=t+*itr;
        return t;
    };
};
MatrixElem**me;
void Initialize(unsigned int n)
{
    me=new MatrixElem*[n];
    for(int i=0;i<n;i++)
        me[i]=new MatrixElem[n];
}
void FreeElem(unsigned int n)
{
    for(int i=0;i<n;i++)
        delete []me[i];
    delete me;me=0;
}
MyVector<MatrixElem> mv;
/*将用到的一些全局变量*/
int total=99999;
int result;
unsigned int N;//矩阵边长
void Scan(int y)
{
    int i;MatrixElem tmp;
    if(mv.size()!=N)
    {
        for(i=0;i<N;i++)
        {
            tmp=me[i][y];
            if(!mv.find(tmp))
            {
                mv.push_back(tmp);
                Scan(y+1);//扫下一行
                mv.pop_back();
            }
        }
    }
    else
    {
        result=mv.sum().n;/*result, 全局变量, 保存相加结果*/
        if(result<total) total=result;
        return;
    }
}
int main()
{
    cout<<"请输入矩阵边长:";cin>>N;
    Initialize(N);
    for(int i=0;i<N;i++)
        for(int j=0;j<N;j++)
        {
            me[i][j].n=(unsigned int)rand()%20;
            me[i][j].x_ordinate=j;        //把二维数组下标变成类的成员变量
            me[i][j].y_ordinate=i;        //把二维数组下标变成类的成员变量
        }
    for(i=0;i<N;i++)
    {
        for(int j=0;j<N;j++)
            cout<<me[i][j].n<<'\t';
        cout<<endl;
    }
    Scan(0);
    cout<<"最小和:"<<total<<endl;
    return 0;
}

算到10花近半分钟
2017-04-18 17:36
九转星河
Rank: 19Rank: 19Rank: 19Rank: 19Rank: 19Rank: 19
来 自:长长久久
等 级:贵宾
威 望:52
帖 子:5023
专家分:14003
注 册:2016-10-22
收藏
得分:0 
谢各位回复了~现在不得不去上课~回来再对提供的代码进行深度测试~先谢过了~

[code]/*~个性签名:bug是什么意思?bug是看上去没有可能的东西实际上是有可能做到的 就是这样~2018-08-08更~*/[/code]
2017-04-18 19:24
九转星河
Rank: 19Rank: 19Rank: 19Rank: 19Rank: 19Rank: 19
来 自:长长久久
等 级:贵宾
威 望:52
帖 子:5023
专家分:14003
注 册:2016-10-22
收藏
得分:0 
回复 20楼 azzbcc
这个代码感觉很好~先回复自己一下~



以下是引用九转星河在2017-4-17 19:08:36的发言:

任意交换两个数最优解的和都会增大这个没啥好证明的~但现在纠结的是它的逆命题~任意交换两个数其和都会增大的必然是最优解~这个命题是否成立~~~



找了个反例验证逆命题是不成立的~
用你的那个代码测试了一下~
图片附件: 游客没有浏览图片的权限,请 登录注册

不过看到输出结果还是存在最小值还是笑了~~

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

图片附件: 游客没有浏览图片的权限,请 登录注册


其实我可以理解就是每行每列都取最小值优先选择~
但这样取法不一定确保是最优解的~

这题最小值应该是8~

其实我同学的想法和你一样我就去验证了一下~在此之前我已经收集了一些反例~所以很快就能看出代码漏洞了~~~

[code]/*~个性签名:bug是什么意思?bug是看上去没有可能的东西实际上是有可能做到的 就是这样~2018-08-08更~*/[/code]
2017-04-18 22:32
寒风中的细雨
Rank: 17Rank: 17Rank: 17Rank: 17Rank: 17
等 级:贵宾
威 望:66
帖 子:1710
专家分:8645
注 册:2009-9-15
收藏
得分:5 
回复 25楼 九转星河
算法应该是可以的, 代码没有考虑全

思路是这样子的:  题目要求是求最小值, 那么确保取到的N个数  为合法的最小值即可

  N*N 个数全排列,  从大到小, 逐一将大的数字去掉, 当每行/列  剩余一个数的时候, 这个数需要取

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

第一次取 1
第二次取 4
第三次取 1
最四次取 2
2017-04-18 23:33
寒风中的细雨
Rank: 17Rank: 17Rank: 17Rank: 17Rank: 17
等 级:贵宾
威 望:66
帖 子:1710
专家分:8645
注 册:2009-9-15
收藏
得分:5 
回复 26楼 寒风中的细雨
程序代码:

 ~/test # ./tesst 
4
6 2 3 5
3 7 4 1
4 1 8 6
7 2 1 9
(1, 3) (2, 0) (0, 1) (3, 2) 

 sum[8]

 ~/test # ./tesst 
3
1 2 3
2 3 4
3 4 5
(2, 0) (1, 1) (0, 2) 

 sum[9]

 ~/test # ./tesst 
4
1 3 5 7
1 1 3 5
3 1 1 3
5 3 1 1
(0, 0) (3, 3) (1, 1) (2, 2) 

 sum[4]

 ~/test # ./tesst 
3
1 3 4
2 2 3
3 1 2
(0, 0) (1, 1) (2, 2) 

 sum[5]

 ~/test # 

程序代码:
#include <stdio.h>
#include <assert.h>

#define    MAX_ARY_LEN        (100)
#define INVALID_VAL        (0xffffffff)    ///< 最大值

unsigned int ary_len;
unsigned int two_ary[MAX_ARY_LEN][MAX_ARY_LEN];
struct{
        
    unsigned int row;    ///< 行
    unsigned int col;    ///< 列
    unsigned int val;    ///< 值
}list_st[MAX_ARY_LEN * MAX_ARY_LEN];
unsigned int row_ary[MAX_ARY_LEN];
unsigned int col_ary[MAX_ARY_LEN];

/**

 *\brief 捕获输入

 */
void get_input(void)
{
    unsigned int i = 0, j = 0;
    
    scanf("%u", &ary_len);
    
    assert(ary_len > 1 && ary_len <= 100);
    for (i = 0; i < ary_len; ++i){
        
        for (j = 0; j < ary_len; ++j){
            
            scanf("%u", &two_ary[i][j]);
            list_st[i * ary_len + j].row = i;
            list_st[i * ary_len + j].col = j;
            list_st[i * ary_len + j].val = two_ary[i][j];
        }
        
        row_ary[i] = ary_len;
        col_ary[i] = ary_len;
    }    
}

/**

 *\brief 对list_st 排序

 */
void sort_list(void)
{
    unsigned int total = ary_len * ary_len;
    unsigned int i = 0, j = 0;
    
    /* 选择 */
    for (i = 0; i < total; ++i){
        
        for (j = i + 1; j < total; ++j){
            
            if (list_st[i].val < list_st[j].val){
            
                list_st[i].row += list_st[j].row;
                list_st[i].col += list_st[j].col;
                list_st[i].val += list_st[j].val;
                list_st[j].row = list_st[i].row - list_st[j].row;
                list_st[j].col = list_st[i].col - list_st[j].col;
                list_st[j].val = list_st[i].val - list_st[j].val;
                list_st[i].row -= list_st[j].row;
                list_st[i].col -= list_st[j].col;
                list_st[i].val -= list_st[j].val;                
            }
        }
    }
}

/**

 *\brief 选择

 */
void select_num(void)
{
    unsigned int total = ary_len * ary_len;
    unsigned int i = 0, j = 0, k = 0, sum = 0;
    
    /* 选择 */
    for (i = 0; i < total; ++i){
        
        unsigned int row = list_st[i].row;
        unsigned int col = list_st[i].col;
        
        if (two_ary[row][col] == INVALID_VAL){
        
            continue;
        }
        
        if (row_ary[row] > 1 && col_ary[col] > 1){
            
            --row_ary[row];
            --col_ary[col];
            two_ary[row][col] = INVALID_VAL;
        }

        if(row_ary[row] == 1){/* 行唯一 */
        
            for (j = 0; j < ary_len; ++j){
                
                if (two_ary[row][j] != INVALID_VAL){/* 在单行上搜索 */
                    
                    sum += two_ary[row][j];
                    printf("(%u, %u) ", row, j);
                    two_ary[row][j] = INVALID_VAL;
                    row_ary[row] = 0;
                    col_ary[j] = 0;
                    break;
                }
            }
            
            for (k = 0; k < ary_len; ++k){    
            
                if (row_ary[k] > 0 && two_ary[k][j] !=  INVALID_VAL){/* 处理所有受影响行 */
                    
                    --row_ary[k];
                    two_ary[k][j] =  INVALID_VAL;
                }                
            }
        }
        
        if(col_ary[col] == 1){/* 列唯一 */

            for (j = 0; j < ary_len; ++j){
                
                if (two_ary[j][col] != INVALID_VAL){/* 在单列上搜索 */
                    
                    sum += two_ary[j][col];
                    printf("(%u, %u) ", j, col);
                    two_ary[j][col] = INVALID_VAL;
                    row_ary[j] = 0;
                    col_ary[col] = 0;
                    break;
                }
            }
            
            for (k = 0; k < ary_len; ++k){    
            
                if (col_ary[k] > 0  && two_ary[j][k] !=  INVALID_VAL){/* 处理所有受影响列 */
                    
                    --col_ary[k];
                    two_ary[j][k] =  INVALID_VAL;
                }                
            }        
        }
    }
    
    printf("\n sum[%u]\n", sum);
}

int main(void)
{
    get_input();
    
    sort_list();
    
    select_num();
    
    return 0;
}
2017-04-19 00:54
九转星河
Rank: 19Rank: 19Rank: 19Rank: 19Rank: 19Rank: 19
来 自:长长久久
等 级:贵宾
威 望:52
帖 子:5023
专家分:14003
注 册:2016-10-22
收藏
得分:0 
回复 27楼 寒风中的细雨
图片附件: 游客没有浏览图片的权限,请 登录注册


看来还是全排列遍历最稳定~

这题性质感觉和整数划分求平方和的最小值那贴一样~感觉这样取巧不一定能得到最优解~不过还是可以得到一个非常不错的解的~而且赢得了大量的运算时间~

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


[code]/*~个性签名:bug是什么意思?bug是看上去没有可能的东西实际上是有可能做到的 就是这样~2018-08-08更~*/[/code]
2017-04-19 07:33
寒风中的细雨
Rank: 17Rank: 17Rank: 17Rank: 17Rank: 17
等 级:贵宾
威 望:66
帖 子:1710
专家分:8645
注 册:2009-9-15
收藏
得分:15 
回复 28楼 九转星河
程序代码:
3
1 5 5
1 5 5
8 9 9
(0, 0) (1, 1) (2, 2) 

 sum[15]

程序代码:
#include <stdio.h>
#include <assert.h>

#define    MAX_ARY_LEN        (100)

unsigned int ary_len;
unsigned int two_ary[MAX_ARY_LEN][MAX_ARY_LEN];
struct{
        
    unsigned int row;    ///< 行
    unsigned int col;    ///< 列
    unsigned int val;    ///< 值
}sel_list_st[MAX_ARY_LEN];

/**

 *\brief 捕获输入

 */
void get_input(void)
{
    unsigned int i = 0, j = 0;
    
    scanf("%u", &ary_len);
    
    assert(ary_len > 1 && ary_len <= 100);
    for (i = 0; i < ary_len; ++i){
        
        for (j = 0; j < ary_len; ++j){
            
            scanf("%u", &two_ary[i][j]);
            if (i == j){
            
                sel_list_st[i].row = i;
                sel_list_st[i].col = j;
                sel_list_st[i].val = two_ary[i][j];
            }
        }
    }    
}

/**

 *\brief 调整

 */
void adjust_sel(void)
{
    unsigned int i = 0, j = 0, k = 0, sum = 0;
    
    for (i = 0; i < ary_len; ++i){
        
        for (j = 0; j < ary_len; ++j){
            
            if (i == j){
                
                continue;
            }
            
            unsigned int old_sum = 0, new_sum = 0;
            
            old_sum = sel_list_st[i].val + sel_list_st[j].val;
            /* 调换列位置 */
            new_sum = two_ary[sel_list_st[i].row][sel_list_st[j].col] + two_ary[sel_list_st[j].row][sel_list_st[i].col];
            if (new_sum < old_sum){
                
                sel_list_st[i].val = two_ary[sel_list_st[i].row][sel_list_st[j].col];
                sel_list_st[j].val = two_ary[sel_list_st[j].row][sel_list_st[i].col];
                sel_list_st[i].col += sel_list_st[j].col;
                sel_list_st[j].col = sel_list_st[i].col - sel_list_st[j].col;
                sel_list_st[i].col -= sel_list_st[j].col;
            }
        }
    }
    
    for (i = 0; i < ary_len; ++i){
        
        sum += sel_list_st[i].val;
        printf("(%u, %u) ", sel_list_st[i].row, sel_list_st[i].col);
    }
    
    printf("\n sum[%u]\n", sum);
}

int main(void)
{
    get_input();
    
    adjust_sel();
    
    return 0;
}


2017-04-19 12:57
九转星河
Rank: 19Rank: 19Rank: 19Rank: 19Rank: 19Rank: 19
来 自:长长久久
等 级:贵宾
威 望:52
帖 子:5023
专家分:14003
注 册:2016-10-22
收藏
得分:0 
有一个思路可以试试~就是可以先取两行两列求这个最优解~然后新增一行一列~再调整最优解~如果能找到一个取值法则能使n为最优解的时候推导出n+1的最优解问题就解决了~

[code]/*~个性签名:bug是什么意思?bug是看上去没有可能的东西实际上是有可能做到的 就是这样~2018-08-08更~*/[/code]
2017-04-20 19:26
快速回复:一个关于方阵数组取值问题~
数据加载中...
 
   



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

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