work3

HOMEWORK-03

红字部分为组员修改的意见

文件介绍

在EXE文件夹中的main.exe文件为本项目执行文件直接点击即可,CODE文件夹中的C文件夹中包含了算法部分的代码,其编译出的DLL文件在bin文件夹中,另外在CODE文件夹下的python文件为本项目GUI实现,其样本XML在UI文件夹中。

项目回顾

对于HOMEWORK-02,-a的模式进行了改进,(HOMEWORK-02参见链接
)由于图的规模不容易控制(如果是正负间隔的数据情况则无法使用并查集缩点):

样例1:

    4 4

    1 -2 3 -4

    -5 6 -7 8

    9 -10 11 -12

    -13 14 -15 16

所以在这里我认为很难有一个合适的算法进行-a的操作,我选择使用SAA退火算法,退火时MaxS表示当前状态下选择的最优状态,而RanS表示随意扩展的一个状态,比较这两个状态来判断是否应该选取局部优解,而在大多数情况下该退火算法会得到最优解:

SAA

    void SAA(int v,float T,float r,float Tmin)

    {

        int i,max,maxS=0,ranS,tmp,SMR,sum,ri,j;//State

        struct link * p;

        srand(time(0));

        sum=value[v];

        for(i=0;i<1024;i++){visited[i]=0;available[i]=0;}

        topq=0;p=g[v];visited[v]=1;

        while (p!=NULL)

        {

            if (!visited[p->t]){available[p->t]=1;}

            p=p->next;

        }

        while(1)

        {

            max=-10000000;

            ri=0;

            for (i=0;i<num;i++)

            {

                if (visited[i]) {continue;}

                if (available[i])

                {

                    tmp=estimate(i);

                    if (tmp>max)

                    {

                        max=tmp;

                        maxS=i;

                    }

                    ri++;

                }

            }

            if (ri==0) {break;}

            ranS=rand()%ri+1;

            for (i=0;i<num;i++)

            {

                if (available[i]&&!visited[i])

                {

                    ranS--;

                    if (ranS==0)

                    {

                        ranS=i;

                        break;

                    }

                }

            }

            if (visited[ranS]||!available[ranS]) {return ;}

            SMR=0;

            tmp=estimate(maxS);

            if (sum+tmp>totalmax) {totalmax=sum+tmp;pseudoexpand(maxS);}

            if (tmp>0){SMR=1;}

            else

            {

                if (exp(tmp/T)>(rand()%10000)/10000.0){SMR=1;}

            }

            T*=r;

            tmp=SMR==1?estimate(maxS)-estimate(ranS):estimate(ranS);

            if (sum+estimate(ranS)>totalmax) {totalmax=sum+estimate(ranS);pseudoexpand(ranS);}

            if (exp(tmp/T)>(rand()%10000)/10000.0){SMR=2;}

            T*=r;

            switch(SMR)

            {

                case 1:sum+=expand(maxS);break;

                case 2:sum+=expand(ranS);break;

            }

            if (T<Tmin){break;}

            if (sum>totalmax) {totalmax=sum;printf("%d\n",totalmax);for (j=0;j<1024;j++){chosen[j]=visited[j];}}

        }

    }

退火算法详情参见链接
通过五次相同的退火过程,在每次退火过程中设置1000*V(V表示点数)次初始温度,得到一个相当优的解,其很大程度上就是最优解。 然后对于这个较优解继续进行比较简单的提升通过patch()函数。

patch

    void patch()

    {

        int i,j,sum,yes;

        struct link * p,*q;

        while(1)

        {

            yes = 0;

            for (i=0;i<num;i++)

            {

                if (value[i]>0&&!chosen[i])

                {

                    for (j=0;j<1024;j++) {visited[j]=0;}

                    q = DFS(i);

                    p = q;

                    if (p==NULL)

                    {

                        continue;

                    }

                    sum = p->s;

                    if (sum>=0)

                    {

                        yes = 1;

                        while (q!=NULL)

                        {

                            chosen[q->t] = 1;

                            q = q->next;

                        }

                    }

                }

            }

            if (yes==0) {break;}

        }

    }

 

    struct link * DFS(int v)

    {

        struct link * p;

        struct link * q;

        struct link * tmp;

        int result=-100000;

        p = g[v];

        visited[v] = 1;

        q = (struct link *)malloc(sizeof(struct link));

        q->next = NULL;q->s = value[v];q->t = v;

        while (p!=NULL)

        {

            //printf("%d %d %d\n",p->t,visited[p->t],chosen[p->t]);

            if (chosen[p->t])

            {

                visited[v] = 0;

                q->next = NULL;q->s = value[v];q->t = v;

                return q;

            }

            if (visited[p->t]||value[p->t]>0)

            {

                p=p->next;

                continue;

            }

            if (value[p->t]<0&&!chosen[p->t])

            {

                tmp = DFS(p->t);

                if (tmp!=NULL&&result<tmp->s+value[v])

                {

                    result = tmp->s+value[v];

                    q->next = tmp;

                    q->s=tmp->s+value[v];

                }

            }

            p = p->next;

        }

        visited[v] = 0;

        if (q->next!=NULL) return q;

        return NULL;

    }

将其余有正收益的点不断选取,得到最后的一个局部不可扩充的最优解。 本算法基于时间上的考虑进行了一部分取舍,首先理想情况下应该是通过patch()操作之后得到状态RanS与MaxS,其次patch无法对以下情况进行扩充,以下的情况必须由SAA在退火过程中选取:

样例2:

    3 3

    4 -100 100

    -5 100 100

    4 -100 100

两个价值为4的点都无法被patch(),但由于规模小可以在SAA的过程中被挑选出来,于是仍能得到最优解。 另外-v -h参数对-a参数来说只是建图的方式有所不同。

setgraph:

    void setgraph(int vertical,int horizontal)

    {

        int i1,j1,i,j,yes;

        struct link * p;

        num=0;

        for (i=0;i<n;i++){for (j=0;j<m;j++){father[i][j]=i*m+j;}}

        for (i=0;i<n;i++)

        {

            for (j=0;j<m;j++)

            {

                h[i][j]=0;

                father2g[i*m+j]=-1;

                if (a[i*m+j]>=0)

                {

                    if (i>0&&a[(i-1)*m+j]>=0){father[fatherfind(i,j)/m][fatherfind(i,j)%m]=father[fatherfind(i-1,j)/m][fatherfind(i-1,j)%m];}

                    if (i==0&&a[(n-1)*m+j]>=0&&vertical){father[fatherfind(i,j)/m][fatherfind(i,j)%m]=father[fatherfind(n-1,j)/m][fatherfind(n-1,j)%m       ];}

                    if (j>0&&a[i*m+j-1]>=0){father[fatherfind(i,j)/m][fatherfind(i,j)%m]=father[fatherfind(i,j-1)/m][fatherfind(i,j-1)%m];}

                    if (j==0&&a[i*m+m-1]>=0&&horizontal){father[fatherfind(i,j)/m][fatherfind(i,j)%m]=father[fatherfind(i,m-1)/m][fatherfind(i,m-1)%m       ];}

                }

            }

        }

        for (i=0;i<n;i++)

        {

            for (j=0;j<m;j++)

            {

                if (a[i*m+j]>0)

                {

                    if (father2g[fatherfind(i,j)]==-1)

                    {

                        father2g[fatherfind(i,j)]=num;

                        value[num]=a[i*m+j];

                        g[num]=NULL;

                        num++;

                    }

                    else{value[father2g[fatherfind(i,j)]]+=a[i*m+j];}

                }

                else

                {

                    value[num]=a[i*m+j];

                    father2g[i*m+j]=num;

                    g[num]=NULL;

                    num++;

                }

            }

        }

        for (i=0;i<n;i++)

        {

            for (j=0;j<m;j++)

            {

                for (shifter=0;shifter<4;shifter++)

                {

                    i1=i+shifti[shifter];

                    j1=j+shiftj[shifter];

                    if (i1<0||i1>=n)

                    {

                        if (vertical) {i1=(i1+n)%n;}

                        else {continue;}

                    }

                    if (j1<0||j1>=m)

                    {

                        if (horizontal) {j1=(j1+m)%m;}

                        else {continue;}

                    }

                    p=g[father2g[fatherfind(i,j)]];

                    yes=1;

                    while (p!=NULL)

                    {

                        if (p->t==father2g[fatherfind(i1,j1)])

                        {

                            yes=0;

                            break;

                        }

                        p=p->next;

                    }

                    if (yes)

                    {

                        p=(struct link*)malloc(sizeof(struct link));

                        p->next=g[father2g[fatherfind(i,j)]];

                        p->t=father2g[fatherfind(i1,j1)];

                        p->s=value[p->t]>=0?1:0;

                        g[father2g[fatherfind(i,j)]]=p;

                    }

                }

            }

        }

    }

GUI构架简介

出于平台兼容性考虑使用的是pythonQT的GUI形式,其中表格部分为输入部分,取一个最小的能包含所有输入部分的矩形作为输入成分,其中没有输入的部分认为输入的0,一共有两个Tab卡可以进行两个矩阵的输入操作。OK键表示根据右侧选项check后将其提交运算,标黄的为选择的部分。RESET会将所有数字清空。在一开始,我一不小心把UI文件中增加了计算成分,但在组员的提醒下,我分开了这两部分,把计算部分作为一个子类继承UI类,在其中重写一些按钮的方法,并加入计算成分。并且将调用算法的模式敲定为dll调用。

项目流程

首先通过C写算法部分的代码,在组员的提醒下,了解到啊并不需要在C的情况下写界面,由此换用更加高效的开发方式,介于MFC已经过时,我们没有采取这种VC6.0时代的组建方式。而对于C#构建的界面,虽然已然开发起来很方便,但仍然不具备跨平台的特点,于是我们组准备使用QT。为了体验一次跨语言编程架构的感觉,我们最终敲定使用PYQT。

而现在对.h文件有了更加深入的理解,即只声明而不划分内存,这与之前浅薄的了解不同,.h并不意味着是一个函数库,dll才是,.h只是起一个声明作用,其作用举一例说明便是把.h.dll都发送给二次编写者,以此保证其对自己的依赖性的同时不泄露代码,而GUI部分则无需要特别好的实现效率,于是便使用了PYQT的高开发效率的特性。并且学会了使用md语言。先使用ERIC4提供的QTdesigner绘制框架再通过ERIC4向python编译,再用自己写的窗口类继承setui后,完成GUI设计流程。

 

 

Personal Software Process Stages

时间百分比(%)

实际花费的时间 (分钟)

原来估计的时间 (分钟)

Planning

计划

 10

 

·         Estimate

·         估计这个任务需要多少时间,把工作细化并大致排序

 10

 

 

Development

开发

 80

 

 

·         Analysis

·         需求分析 (包括学习新技术)

 15

 

 

·         Design Spec

·         生成设计文档

 10

 

 

·         Design Review

·         设计复审 (和同事审核设计文档)

 5

 

 

·         Coding Standard

·         代码规范 (制定合适的规范)

 10

 

 

·         Design

·         具体设计

 5

 

 

·         Coding

·         具体编码

 15

 

 

·         Code Review

·         代码复审

 5

 

 

·         Test

·         测试(自我测试,修改代码,提交修改)

 15

 

 

Reporting

总结报告

 10

 

 

·         Test Report

·         测试报告

 5

 

 

·         Size Measurement

·         计算工作量

 3

 

 

·         Postmortem & Improvement Plan

·         事后总结, 并提出改进

 2

 

 

Total

总计

100%

总用时

总估计的用时 系数为5小时,与计划差不多~

 

 

posted on 2013-10-20 23:26  Yuzuka  阅读(316)  评论(1编辑  收藏  举报

导航