关键路径——杭电 4109

来源:互联网 发布:adobereader破解版mac 编辑:程序博客网 时间:2024/06/05 08:57

--------------------------11月23日-------------------------

昨天和今天一直在写一道题,杭电的4109

题目不难,可是我的经验实在是太少了。题目就是一道关键路径的。光把用邻接表求关键路径给写出来就写了两三个小时,然后还修复了两个小错误。提交上去仍然是re。到现在还是没找出来为什么。在数据量小于10的时候可以正常结束。但是一旦数据大于10个了就只是能输出答案,然后就不能正常结束了。

看到别人的博客真心着急啊。别人差不多每天两三道题的速度在往前飞跃,而我却两三天一道题的速度在往前慢慢爬。差距怎么就这么大

下面是这次的代码(这个代码就不用认认真真看了,基本就是数据结构书上面的内容,只是拿出来做一下反例,重点是后面所学到的东西)

#include<iostream>#include<stack>#include<string.h>using namespace std;#define MAXinstr 2000  //the max number of instructions#define ERROR 0;#define OK 1;int ve[MAXinstr],vl[MAXinstr];typedef struct ArcNode{int adjvex;struct ArcNode *nextarc;int info;}ArcNode;typedef struct VNode{int data;ArcNode *firstarc;}VNode,AdjList[MAXinstr];typedef struct {AdjList instruction;       //the list of instructionsint vexnum,arcnum;}ALGraph;void FindInDegree(ALGraph G,int indegree[]){        //get indegree of every verticsArcNode *p;for(int i=0;i<G.vexnum;i++){indegree[i]=0;}for(int i=0;i<G.vexnum;i++){for(p=G.instruction[i].firstarc;p;p=p->nextarc){indegree[p->adjvex]++;}}}int TopologicalOrder(ALGraph G,int T[]){int *indegree=(int*)malloc(sizeof(int)*(G.arcnum+10));FindInDegree(G,indegree);int count=0;for(int i=0;i<G.vexnum;++i){ve[i]=0;}int S[MAXinstr];int Snum=0;for(int i=0;i<G.vexnum;++i){if(!indegree[i]){S[Snum]=i;Snum++;}}ArcNode *p;int tmp=0;while(Snum){int j=S[Snum-1];Snum--;T[tmp]=j;count++;for(p=G.instruction[j].firstarc;p;p=p->nextarc){int k=p->adjvex;indegree[k]--;if(!indegree[k]){S[Snum]=k;Snum++;}if(ve[j]+p->info>ve[k])ve[k]=ve[j]+p->info;}//for}//whileif(count<G.vexnum)return 0;return 1;}int CriticalPath(ALGraph G){int T[MAXinstr];if(!TopologicalOrder(G,T))return ERROR;for(int i=0;i<G.vexnum;++i){vl[i]=ve[i];}int tmp=G.vexnum-1;while(tmp>=0){int j=T[tmp];tmp--;ArcNode *p;for(p=G.instruction[j].firstarc;p;p=p->nextarc){int t=p->adjvex;int dut=p->info;if(vl[t]-dut>vl[j])vl[j]=vl[t]-dut;}//for}//while/*for(int i=0;i<G.vexnum;++i){ArcNode *p;for(p=G.instruction[i].firstarc;p;p=p->nextarc){int k=p->adjvex;int dut=p->info;int ee=ve[i];int el=vl[k]-dut;if(ee==el){CPath[CP]=i;CP++;}}}*/return OK;}int CreateALGraph(ALGraph &G,int vertixnum,int arc){G.vexnum=vertixnum;G.arcnum=arc;for(int i=0;i<G.vexnum;++i){G.instruction[i].firstarc=NULL;}for(int i=1;i<=G.arcnum;++i){int j,k,dur;cin>>j>>k>>dur;j--;k--;ArcNode *p;p=G.instruction[j].firstarc;while(p&&p->nextarc)p=p->nextarc;ArcNode *tmp=(ArcNode*)malloc(sizeof(ArcNode));tmp->info=dur;tmp->adjvex=k;if(!p)G.instruction[j].firstarc=tmp;elsep->nextarc=tmp;tmp->nextarc=NULL;}return OK;}int main(){int m,n;cin>>m>>n;ALGraph G;CreateALGraph(G,m,n);CriticalPath(G);int maxCP=0;for(int i=0;i<G.vexnum;++i){if(maxCP<vl[i])maxCP=vl[i];}cout<<maxCP+1<<endl;return 0;}

如果输入像30 0这样的数据,可以正确的输出结果,但是结果输出以后就崩溃了。怎么一个return 0 都这么虐我了0.0

------------------------------11月28日--------------------------------------


对于输入30 0 这样的数据会崩溃的问题,今天终于找到问题的原因了。因为在代码中搞了太多很大很大的数组,而且这些数组都放在了局部变量里面。对于需要用到很大的数组的程序,大数组一定要放在全局变量里面,否则程序就会很莫名其妙的崩溃,就像前几天的我那样……


-------------------------12月1日--------------------------------------------

今天终于把这道题给解决了,而且从中学到了好多东西。

首先是放弃了原来写出来的代码,参考了别人大神的博客   http://blog.csdn.net/kkkwjx/article/details/12257829

这种做法是用邻接矩阵来表示的,没有用邻接表的办法。不过仔细想想,邻接矩阵虽然存储空间会比邻接表大,但是临街矩阵的处理速度就比邻接表快多了,邻接表需要申请空间什么的一大堆东西。

接下来是代码(这个就是可以通过的代码了)

#include<iostream>#include<stdio.h>#include<stack>using namespace std;#define MAXN 1005int g[MAXN][MAXN];int topo[MAXN];int el[MAXN];int main(){int m,n;while(scanf("%d%d",&n,&m)!=EOF){//n instructions,m vertixesmemset(g,0,sizeof(g));memset(el,0,sizeof(el));memset(topo,0,sizeof(topo));int ind[MAXN]={0},Ind[MAXN]={0};int x,y,z;for(int i=0;i<m;++i){scanf("%d%d%d",&x,&y,&z);//第一次写的时候这里用的是cin,为什么改成scanf是有原因的,看下面的分析~~~if(!g[x][y]){g[x][y]=z;ind[y]++;Ind[y]=ind[y];}}stack<int> S;for(int i=0;i<n;++i){if(!ind[i])S.push(i);}int p=0;while(!S.empty()){int gettop=S.top();S.pop();topo[p++]=gettop;for(int i=0;i<n;++i){if(g[gettop][i]){ind[i]--;if(!ind[i])S.push(i);}}}//whileint mx=0;for(int i=0; i<n; ++i)        {            int pos=topo[i];            if(!Ind[pos])el[pos]=0;            else            {                for(int t=0; t<n; ++t)                    if(g[t][pos])                        el[pos]=max(el[t]+g[t][pos],el[pos]);                mx=max(mx,el[pos]);            }        }cout<<mx+1<<endl;}return 0;}

算法的思想跟邻接表一模一样,可以看得出来用邻接矩阵使代码简洁了快100行

接下来是在做这道题的过程中遇到的东西。

第一次在写这段代码的时候,输入边以及权值的时候,我用的是cin而不是scanf,然后就一直超时,仔仔细细的跟人家的代码对比了几遍都没找出来什么原因,然后就把别人的循环一段一段的往自己的代码上面复制,希望能找到什么原因。一直复制到输入的那个循环的时候终于找到问题了。于是就开始找百度原因。后来知道了原来用scanf函数比用cin要快好多。(用cin的时候运行在1秒以上,而用scanf以后运行时间是260多毫秒,速度差距了将近五倍)。默认情况,cin与stdin总是保持同步的,也就是说这两种方法可以混用,而不必担心文件指针混乱,同时cout和stdout也一样,两者混用不会输出顺序错乱。正因为这个兼容性的特性,导致cin有许多额外的开销,如何禁用这个特性呢?只需一个语句std::ios::sync_with_stdio(false);,这样就可以取消cin于stdin的同步了,此时的cin就与scanf差不多了。(这句话复制了这篇文章中的原话http://hi.baidu.com/i5love1you9/item/2b97cb3dd91f20b7134b14c5)


到今天为止这道题终于算是完成了,从这道题中可以学到两点做算法题目的时候的技巧,首先,在开数组的时候,如果数组空间比较大,那么就要把数组声明为全局变量,要不然程序很容易就崩溃了。第二,在OJ上面做题的时候,如果有很大的数据输入,就不要用cin,用scanf,或者按章上面那篇文章中的取消cin与stdin的同步然后再用cin。另外,这是一道模板类型的题目。

原创粉丝点击