pat-1003 经典模板深度剖析

人总要摸着石头过河~错误都是难得的经验 

#include<iostream>
#include<vector>
#include<algorithm>
using namespace std;
int sr,endd,w[510],tempw=0,maxt=0,a[510][510],cnt=0,dsr[510],visit[510]={0};//w0-n w[0]=1
const int inf=1000000000;
vector<int> pre[510],tempath;
/*void dfs(int fin){
   	tempw+=w[fin];
	if(fin==sr){
		if(tempw>maxt){
			maxt=tempw;
			tempw=tempw-w[sr];//因为此时下一次递归只出去了最后一个前面的都要保留(注意) 
			//return 位置弄错导致cnt没记上去 
		}
		cnt++;
		return;
	}
	for(int i=0;i<pre[fin].size();i++){
  		dfs(pre[fin][i]);//完成之后退回来会直接加下一个孩子所以源点end的值没加 
	}
} */
void dfs(int f){
	//END
	if(f==sr){
		tempath.push_back(sr);
		tempw=0;//条件重置不能前面影响后面 
		for(int j=tempath.size()-1;j>=0;j--){
			tempw+=w[tempath[j]]; //加的应该是tempath里面的索引号各种路径终不能是递减的 双索引的情况(注意) 
		}
		if(tempw>maxt){
			maxt=tempw;
			//若有path还要更新path   path=tempath 
		}
		cnt++;
		tempath.pop_back();
		return;//return一定要放到最后 
	}
	tempath.push_back(f);
	for(int i=0;i<pre[f].size();i++){
		dfs(pre[f][i]);
	}
	tempath.pop_back();
}
int main(){
	int n,m,ttw,_1,_2,_3;
	cin>>n>>m>>sr>>endd;
	fill(dsr,dsr+510,inf);
	fill(a[0],a[0]+510*510,inf);
	for(int i=0;i<n;i++){
		cin>>ttw;
		w[i]=ttw;
	}
	for(int i=0;i<m;i++){
		cin>>_1>>_2>>_3;
		a[_1][_2]=a[_2][_1]=_3;
	}
	dsr[sr]=0;
	for(int i=0;i<n;i++){
		int u=-1,minn=inf;
		for(int j=0;j<n;j++){
			if(visit[j]==0&&dsr[j]<minn){
				minn=dsr[j];
				u=j;
			}
		}
		if(u==-1) break;
		visit[u]=1;
		for(int v=0;v<n;v++){
			if(visit[v]==0&&a[u][v]!=inf){
				if(dsr[v]>a[u][v]+dsr[u]){
					dsr[v]=a[u][v]+dsr[u];
					pre[v].clear();
					pre[v].push_back(u);
				}
				else if(dsr[v]==a[u][v]+dsr[u]){//择一 dijsktra最重要的部分掉了个else导致整个出错,else不带pre数组就会出错(注意) 
					pre[v].push_back(u);
				}
			}
		}
	}
	/*for(int i=1;i<=4;i++){
		for(int j=0;j<pre[i].size();j++){
			printf("%d ",pre[i][j]);
			
		}
		printf("\n");
	}  //起点没有前驱(注意) */
	dfs(endd);
	printf("%d %d",cnt,maxt);
	
	return 0;
}

 搞了三个小时吧,期间对dijkstra易错点基本上都弄了一遍实属不易~长话短说

第一遍:没有存储路径,懒吗企图省点力气就在dfs内做了很大的简化,见我注释掉的

确实可以算一条路径的准确权重  但是!!当完成一条后应该弹出一个进行下面的  我直接将temp弄成0天真的以为他能再重新加一遍错了,此时他只会在我弄得0的基础上如果下一个点是最终点只会再加哪一个结束当然错误

反例

4 5 0 3
1 4 1 2
0 1 1
0 2 2
0 3 4
1 2 1
2 3 2
正确答案
3 8

为啥呢

前序数组 注意起点0没有前序
1 :0
2 :0 1
3 :0 2

路径

3->0

3->2->0

3->2->1->0

如果你直接令temp=0or temp=w[end]的话在前序数组中2 遍历完0后会紧接着取遍历1此时temp里面除了有 end 的值还有2的值所以还是不对

第二遍 temp改为 temp=temp-w[sr]  就是减去弹出的的点的值这总行了吧 里面有了出去弹出去的所有的值 不好意思~还有反例

前序数组 注意起点0没有前序
2 :0 
3 :2 0

对前序数组稍作修改
3->2->0
3->0

此时3遍历2,2遍历0到了终点去掉0的值,里面有3,2的值再去遍历0,还是3,2,0,的值本来是3->0,里面只有3,0的值又多了一个

所以用路径存储是正确的temp面对的情况太多不好直接赋值

这两个反例也是为什么 路径存储中为什么那两个pop_back()放在那里的原因,放在return 上面的,是为了解决第一种情况只去源点的情况,放在dfs下面的是为了解决第二个反例,就是源点去了,恰好这一路也结束的情况,要把没用的2 pop_back

通过这两个反例理解了为什么pop_back()的位置放在那里

dijkstra+dfs易错点

1.里面最后一个for循环如果有多种情况,一定要写if  else if ....不能把else弄掉否则第一个if改了条件直接导致第二个if成立就错了

2.不管如何在dfs中必须存储路径,来计算其他性质

3.dfs中 return,应该放在所有该干的事下面不能放在要求的性质的上面

4.注意算性质处的双重索引的情况w[tempath[j]],始终要写路径中的索引别漏写,对于这种判断编写的时候就要带入几个判断一下,避免出错

5.注意求和路径中权值和要条件重置sum=0

 

猜你喜欢

转载自blog.csdn.net/m0_45359314/article/details/112974381
今日推荐