| 网站首页 | 业界新闻 | 小组 | 威客 | 人才 | 下载频道 | 博客 | 代码贴 | 在线编程 | 编程论坛
欢迎加入我们,一同切磋技术
用户名:   
 
密 码:  
共有 4124 人关注过本帖, 1 人收藏
标题:煮酒论英雄 众高手进来坐坐
只看楼主 加入收藏
beyondyf
Rank: 19Rank: 19Rank: 19Rank: 19Rank: 19Rank: 19
等 级:贵宾
威 望:103
帖 子:3282
专家分:12654
注 册:2008-1-21
结帖率:100%
收藏(1)
已结贴  问题点数:100 回复次数:67 
煮酒论英雄 众高手进来坐坐
C论坛热闹有余,但精彩论题不多。基本是新人雀跃,老将藏刀旁观。

大概是高手们厌倦了这里到处都是的入门级(还有部分智障级)的提问,给分也提不起他们的兴趣了。

一旦众高手对这里完全失去了兴趣,这将是论坛的重大损失。(恐怕已经损失不少了)

兄弟斗胆提议,众高手有没有兴趣来下下棋?

当然,各位身在大江南北,想聚大家到一起品茗弈棋是不太可能了。

在网上对弈还是可以的。

不过就这么人和人下棋也没什么意思。不如让我们的程序和程序下棋如何?

众高手要是有兴趣的话就进来咱们议一议。

准备下什么棋、怎么下、程序的通讯接口方式等等。

或哪位有更有趣的并可实现的提议也不妨进来谈谈。(黑五角大楼主机这样的议题就免了,兄弟没那水平)

众英雄,廉颇老矣,尚能饭否?


最后顺道说说有容《大家用计算机解决个实际问题吧。》贴子中提到的问题。原贴见https://bbs.bccn.net/thread-370746-1-1.html

在原贴中我个人悬赏100专家分想激励坛友参与。可惜没什么达到预期的效果。

部分有能力的朋友这两天好像不在,还有一部分可能是不屑于解决这样的问题。

总之,到现在也没有出现让人满意的回答。这让我有一点失望。

在原贴中我说过这个问题的难度分两层。

第一层,找出满足要求的排列。

这一层很基础,不管算法如何,大家基本还是能做到的。

第二层,计算“找到的满足要求的排列”变换到“题目中给出的排列”所需的最少的交换次数。

这一层其实也不难,可惜到现在也没见一个可行的算法模型出来。众坛友的问题建模能力还有待提高。

其实这一层可以归结为图中的最短路径问题。属于图论的知识范畴,我记得以前就有人讨论过Dijkstra算法,完全可以直接应用到这里。

每一个排列可以看作是一个状态结点。

如果一个排列通过交换一对元素的位置可以变成另一个排列,那么用一条边关联这两个排列的状态结点。

由此构成一个图。

在这个理论模型上,连接两个点的最少的边数(也称两点的距离,可以认为每条边的权为1)即是从一个排列变换到另一个排列需要的最少次数。

对于原题,就是找从“728196345”到一个满足第一层要求的结点的距离。

关于最短路径算法我也不想在这里详述了。没学过但有兴趣的朋友,随便找本图论或算法的书看看,里面都会讲到。

最后送上我的代码给各位参考。我使用队列来存储点集,而队列以单向链表构成。各位也可以按自己的想法用数组等等来实现。

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

typedef struct _node
{
    int state;
    int value;
    struct _node * next;
}NODE;

typedef struct
{
    NODE * head;
    NODE * tail;
}QUEUE;

void queue_clear(QUEUE * q)
{
    NODE *p, *t;
    for(p = q->head; p != NULL;)
    {
        t = p;
        p = p->next;
        free(t);
    }
    q->head = NULL;
    q->tail = NULL;
}

int queue_push(QUEUE * q, int state, int value)
{
    NODE *p, *t;
    if((p = (NODE *)malloc(sizeof(NODE))) == NULL) return 0;
    p->state = state;
    p->value = value;
    p->next = NULL;
    if(q->head == NULL) q->head = p; else q->tail->next = p;
    q->tail = p;
    return 1;
}

int queue_pop(QUEUE * q, int * state, int * value)
{
    NODE * p;
    if(q->head == NULL) return 0;
    *state = q->head->state;
    *value = q->head->value;
    p = q->head;
    q->head = q->head->next;
    free(p);
    return 1;
}

int queue_find(QUEUE q, int state)
{
    NODE * p;
    for(p = q.head; p != NULL && p->state != state; p = p->next);
    return p != NULL;
}

int is_legal(int state)
{
    int a, b;
    a = state / 1000000;
    a = a / 100 * (a % 100);
    b = state / 1000 % 1000;
    if(a != b) return 0;
    a = state % 1000;
    a = a / 10 * (a % 10);
    return a == b;
}

int swap(int state, int i, int j)
{
    const int e[] = {1, 10, 100, 1000, 10000, 100000, 1000000, 10000000, 
100000000};
    int a, b;
    a = state / e[i] % 10;
    b = state / e[j] % 10;
    state -= a * e[i];
    state -= b * e[j];
    state += a * e[j];
    state += b * e[i];
    return state;
}

int test(int initState, int * finalState, int * value)
{
    int s, v, ts, i, j;
    QUEUE q = {NULL, NULL};
    queue_push(&q, initState, 0);
    while(queue_pop(&q, &s, &v))
    {
        for(i = 0; i < 9; i++)
        for(j = i + 1; j < 9; j++)
        {
            ts = swap(s, i, j);
            if(is_legal(ts))
            {
                *finalState = ts;
                *value = v + 1;
                queue_clear(&q);
                return 1;
            }
            if(!queue_find(q, ts)) queue_push(&q, ts, v + 1);
        }
    }
    return 0;
}

int main()
{
    int state, value;
    if(test(728196345, &state, &value))
        printf("%d step %d\n", state, value);
    else
        printf("no match.\n");
    return 0;
}


[ 本帖最后由 beyondyf 于 2012-6-6 20:07 编辑 ]
搜索更多相关主题的帖子: 如何 
2012-06-06 20:04
有容就大
Rank: 16Rank: 16Rank: 16Rank: 16
来 自:东土大唐
等 级:版主
威 望:74
帖 子:9048
专家分:14309
注 册:2011-11-11
收藏
得分:5 
杨大哥 磨坊主那个如果朋友们想过了 还是能学到些东西 再看看你给的代码 收获就不小了。
下棋 很有意思 喜欢这个 就不知道怎么拿程序对战 呵呵。

梅尚程荀
马谭杨奚







                                                       
2012-06-06 20:22
beyondyf
Rank: 19Rank: 19Rank: 19Rank: 19Rank: 19Rank: 19
等 级:贵宾
威 望:103
帖 子:3282
专家分:12654
注 册:2008-1-21
收藏
得分:0 
不难,先看看大家的意向。之后我会解释我的方案。如果大家认可,我可以负责对战平台的编写。

重剑无锋,大巧不工
2012-06-06 20:34
小赵q1
Rank: 8Rank: 8
等 级:蝙蝠侠
威 望:4
帖 子:492
专家分:777
注 册:2011-8-26
收藏
得分:5 
杨大哥,小赵感觉越来越力不从心了,学着C语言就想到自己写个小程序来验证下自己对学到东西的理解,但是写程序遇到的问题往往都不能想到一个好的解决方法,比如我想写一个游戏机的程序,在压分的时候考虑怎么实现,但是实际操作的时候别人不一定会按照自己的要求去操作,要限制他们的操作却做不到,比如让他输入的两个数字中间用空格隔开,如果别人偏不用空格,一定要按个回车或者加个字符,程序就会出现不可预知的结果,我想到了用WINDOWS窗口来解决,可是那个东西不是一天两天就可以学好的,理解不透消息产生和发生的过程,就不知道自己写的零件该放在什么位置。
    我是不是该先放下自己的程序,把C语言给彻底学透了再去接触API呢?
2012-06-06 21:25
beyondyf
Rank: 19Rank: 19Rank: 19Rank: 19Rank: 19Rank: 19
等 级:贵宾
威 望:103
帖 子:3282
专家分:12654
注 册:2008-1-21
收藏
得分:0 
回复 4楼 小赵q1
不必。而且我是建议同时学的。

我想你还是心太急了,欲速则不达。

重剑无锋,大巧不工
2012-06-06 21:36
ab1034982749
Rank: 9Rank: 9Rank: 9
等 级:蜘蛛侠
帖 子:215
专家分:1185
注 册:2012-4-14
收藏
得分:5 
围观,围观,
2012-06-06 22:49
czz5242199
Rank: 11Rank: 11Rank: 11Rank: 11
等 级:小飞侠
威 望:4
帖 子:660
专家分:2400
注 册:2011-10-26
收藏
得分:5 
最近期末考试估计是没时间了,不过考完后果断支持
2012-06-06 23:40
pangding
Rank: 19Rank: 19Rank: 19Rank: 19Rank: 19Rank: 19
来 自:北京
等 级:贵宾
威 望:94
帖 子:6784
专家分:16751
注 册:2008-12-20
收藏
得分:5 
记得以前论坛里谁说过,看一个人学有关图的那几个常规算法学得怎么样就能判断他的算法水平好不好。我图论的那几个算法也不是说不会,不过学得确实也不怎么好。

我以前花过半年左右的时间专门研究过(以数学的角度)图论的内容。
有部分人认为图论是人类数学理论的一个重要基础理论,其基础性不亚于数论。其实理论意义(不是指应用意义)远远凛驾于分析学(如微积分)等这些理论之上。可借图论取得的成果太少,很多极为基础性的问题人类没有能力做答。在这一点上,数论要走得深远得多。
有关图有很多基础算法,人们都没能解决。比如人类目前没有判断两张图是否同构的任何有效有效算法。还比如人类相信,现在已知的求图的连通度的最好算法,离它的复杂度下限还有很大的空间(换句话说,优化的可能空间还很多)。

我以前一直以为 ACM 做的多的话,不过也只是对一些比较常用的各类算法掌握的比较熟悉而已。不过后来才明白,即使是把这些常用的算法运用灵活,也需要不少的天赋。所以像 杨大哥,老杨 这些算法高手(也许有很多高手,不过我现在很少来 C 这边,不是很熟悉),从来都是既感且佩。而且代们的代码写出来确实很艺术。
其实 07、08 年那会,论坛里的高手非常多。不过后来也许是有有号召力的高手把大家吸走了。总之这个论坛给人的整体的印象就是定位给辅导初学者的(这个定位感觉我刚来的时候就有)。

其实确实所谓师傅领进门。如果让是我的话,感觉一个够广博的论坛定位面向初学者是很多好处的。比如假如我最近想学 python(确实我有学这个语言的意向),那么我最需要的就是这么一个辅导初学者的地方。基础的语法和表达习惯,以及初学常犯的错误,虽然简单,但是找人带一带能节约很多精力。这时我不在乎大家的编程实力是否比我高,只要他们比我更懂 python 就行。

另外每次一提什么高手过招,经常落到一些老套路里。擅长数值计算的很可能就不太会搞图形,相反也一样。
下棋也差不多,属于人工智能的领域。曾经有一阵子,我对围棋非常感兴趣,研究了很长时间 gnugo(如果大家有兴趣也可以研究研究,gnugo 是开源领域这方面的典范)。后来又读了不少人工智能里有关围棋的 paper。才知道围棋的水有多么深。象棋的复杂度要比围棋低数个数量级,但肯定也不是很容易,要不然 IBM 也不会对“深蓝(deep blue)”如此自豪。另外以前论坛里有人探讨过,五子棋的复杂度比想象得要高很多个数量级,尤其是在带禁手之后。当然除了围棋,其它的我都没什么研究。不过我感觉这些棋类运动之间,除了一些很基本的思想之外,其它的东西都不是很通用(国际象棋和中国象棋可能就算是相通点最多的了)。
2012-06-07 00:04
smallmoon521
Rank: 9Rank: 9Rank: 9
等 级:蜘蛛侠
威 望:4
帖 子:517
专家分:1373
注 册:2008-4-21
收藏
得分:5 
帮顶,提议不错,比谁的象棋算法更具自我学习能力.

希望到时会公开源码, 让我瞻仰一下

为游戏狂~~!!    大家努力编哈!
2012-06-07 08:48
demonleer
Rank: 9Rank: 9Rank: 9
等 级:贵宾
威 望:10
帖 子:483
专家分:1225
注 册:2012-6-4
收藏
得分:0 
我刚来,这帖子还有分给么?

Dijkstra最短路径算法,确实是很妙啊~ 记得以前图论里老师喊的是标记法~

有分的话我想试试~

下午实在憋不住了,丢了工作也要试试~

递归+回溯。

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

int current[9] = {7,2,8,1,9,6,3,4,5};
int backup[9] = {7,2,8,1,9,6,3,4,5};
int buffer[9];

void int_swap(int *p, int i, int j)
{
    if (i!=j)
    {
        int tmp = *(p+i);
        *(p+i) = *(p+j);
        *(p+j) = tmp;
    }
}

void print_step()
{
    int i = 0;
    int j = 0;
    int count = 0;
    for (; i<9; i++)
    {
        if (current[i]!=buffer[i])
        {
            for (j=0; j<9; j++)
            {
                if (buffer[j]==current[i])
                {
                    int_swap(buffer,i,j);
                    count++;
                    printf("step.%d swap %d, %d\n",count,buffer[i],buffer[j]);
                }
            }
        }
    }
}

void array_copytobuffer(int *p)
{
    int i = 0;
    for (; i<9; i++)
    {
        buffer[i] = *p++;
    }
}

int is_stability(int *p)
{
    int left, midl, right,i;
    left = midl = right = 0;
    for (i=0; i<9; i++)
    {
        i<3?(left = left*10 + *p++):1;
        (i>=3&&i<6)?(midl = midl*10 + *p++):1;
        i>=6?(right = right*10 + *p++):1;
    }
    left = (left/100) * (left%100);
    right = (right/10) * (right%10);
    if ((left==midl)&&(right==midl))
    {
        return 1;
    }
    return 0;
}


void print_solution(int *p)
{
    int i = 0;
    for (; i<9; i++)
    {
        printf("%d ",*p++);
    }
    printf("\n");
}

void operation_int(int *p, int level)
{
    if (1==level)
    {
        if (is_stability(current))
        {
            print_solution(current);
            array_copytobuffer(backup);
            print_step();
        }
        return;
    }
    int i=0;
    for (; i<level; i++)
    {
        int_swap(p,0,i);
        operation_int(p+1,level-1);
        int_swap(p,0,i);
    }
}

void main()
{
    operation_int(current,sizeof(current)/sizeof(int));
}


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


[ 本帖最后由 demonleer 于 2012-6-7 17:17 编辑 ]
2012-06-07 08:50
快速回复:煮酒论英雄 众高手进来坐坐
数据加载中...
 
   



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

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