这道题目算法很简单,但是实现代码比较困难。下面是关于该题目的讲解。
首先这是一个填空题,只需要结果,因为在编码时对代码的优化不需要太过于关注。只要保证算法能够在可承受的时间范围内处理数据即可。
关于官方给出的讲解中,利用dfs嵌套dfs来寻路,这实在时有些困难。这不仅需要每次对已经完成的路径进行记录、比较,而且嵌套dfs本身就需要更加严谨的结构。
这里我采用的思路是:dfs找到所有的路,并将该路径对应的权值、路径经过的点、路径的长度记录下来。在记录路径经过的点时,由于后期比较中不再关注路径所经过点的顺序,而只关心路径经过的点是哪些,所以这时对点的编号进行排序,方便后期的比较。这种方法下,我得到了1432条路。然后对所有的路径按照权值和进行排列。然后去重。最后对相同权值的路径进行比较以得到答案273.
代码如下:
1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include<cmath> 5 #include<vector> 6 #include<string> 7 #include<algorithm> 8 using namespace std; 9 10 struct road 11 { 12 int lenth;//路的长度 13 int value;//权值和 14 int list[17];//途径结点 15 bool operator < (const road& rhs) const 16 { 17 return value < rhs.value; 18 } 19 }; 20 21 road allway[3200];//这个大小需要后期运行时尝试 22 int cur=0; 23 vector<int> ver[16];//路信息 24 int pv[]={1,3,2,2,4,2,4,4,7,3,5,6,3,1,5,2}; 25 //保存权值 26 int vis[16]; 27 28 int readin() 29 { 30 for(int i=0;i<18;i++) 31 { 32 int a,b; 33 cin>>a>>b; 34 ver[a].push_back(b); 35 ver[b].push_back(a); 36 }//借助vector数组实现无向图 37 return 0; 38 } 39 40 int w[17];//dfs的路径记录数组 41 int dfs(int nowpoint,int nowvalue,int step) 42 { 43 if(step==15)return 0; 44 //可以采用一笔画的方式估计出最长的路径大约是14 45 if(1)//这里发现路径长度可以为1,原题并没有说明 46 { 47 allway[cur].lenth=step+1; 48 allway[cur].value=nowvalue; 49 memset(allway[cur].list,0,sizeof(int)*17); 50 memcpy(allway[cur].list,w,sizeof(int)*allway[cur].lenth); 51 sort(allway[cur].list,allway[cur].list+step+1); 52 //路径规范化 53 cur++; 54 } 55 //储存计算出的路 56 for(int i=0;i<ver[nowpoint].size();i++) 57 { 58 int next=ver[nowpoint][i]; 59 if(vis[next])continue; 60 vis[next]=1; 61 w[step+1]=next;//记录路径 62 dfs(next,nowvalue+pv[next],step+1); 63 w[step+1]=0;//消除路径记录 64 vis[next]=0; 65 }// 66 return 0; 67 } 68 69 int initial() 70 { 71 freopen("input.txt","r",stdin); 72 readin(); 73 cout<<"READ-OK"<<endl; 74 //路径数据读取完毕 75 cur=0; 76 for(int i=0;i<16;i++) 77 { 78 memset(vis,0,sizeof(vis)); 79 memset(w,0,sizeof(w)); 80 w[0]=i; 81 vis[i]=1; 82 dfs(i,pv[i],0); 83 }//找出所有的路径 84 sort(allway,allway+cur); 85 //按照权值和进行排序 86 //根据后面的去重代码,这句代码其实也没什么必要 87 cout<<"SORT-OK"<<endl; 88 return 0; 89 } 90 91 bool same(road& p1,road& p2)//比较函数 92 { 93 if(p1.value!=p2.value)return false; 94 if(p1.lenth!=p2.lenth)return false; 95 for(int i=0;i<p1.lenth;i++) 96 { 97 if(p1.list[i]!=p2.list[i])return false; 98 } 99 return true; 100 } 101 102 int psort() 103 { 104 initial(); 105 cout<<cur<<endl; 106 // 107 int num=cur; 108 for(int i=0;i<cur;i++) 109 { 110 if(allway[i].value==1000)continue; 111 for(int k=i+1;k<cur;k++) 112 { 113 if(allway[k].value==1000)continue; 114 if(same(allway[i],allway[k])) 115 { 116 allway[k].value=1000; 117 /*C++中对去重的实现方式是将重复的元素放在数组的最后, 118 这里采用那种思想,将重复元素的value的值设置为一个很大的1000 119 然后在最后进行排序,使得所有重复的元素排列到数组最后 120 剩余的前num个路径就是非重复路径*/ 121 num--; 122 } 123 } 124 }//这里的算法可以再优化,不过没什么必要,计算本身很快 125 sort(allway,allway+cur); 126 return num; 127 } 128 129 int ismakepair(road& p1,road& p2)//验证是否可以组成答案 130 { 131 for(int i=0;i<p1.lenth;i++) 132 { 133 int s=p1.list[i]; 134 for(int k=0;k<p2.lenth;k++) 135 { 136 if(s==p2.list[k])return 0; 137 } 138 } 139 return 1; 140 } 141 142 int main() 143 { 144 int num=psort(); 145 int ans=0; 146 for(int i=0;i<num;i++) 147 { 148 for(int k=i+1;k<num;k++) 149 { 150 if(allway[i].value!=allway[k].value)continue; 151 if(ismakepair(allway[i],allway[k]))ans++; 152 } 153 } 154 cout<<ans<<endl; 155 return 0; 156 }
input.txt文件:
0 2 2 1 2 3 1 5 3 7 5 4 5 6 7 6 7 8 4 10 6 12 8 14 10 9 10 11 12 11 12 13 14 13 14 15
OK