zoukankan      html  css  js  c++  java
  • POJ-1724 深搜剪枝

    这道题目如果数据很小的话。我们通过这个dfs就可以完成深搜:

    
    void dfs(int s)
    {
    	if (s==N)
    	{
    		minLen=min(minLen,totalLen);
    		return ;
    	}
    	for (int i=0;i<G[s].size();i++)
    	{
    		Road r=G[s][i];
    		if (r.t+totalCost>K)
    			continue;
    		if (!visited[r.d])
    		{
    			visited[r.d]=1;
    			totalLen+=r.L;
    			totalCost+=r.t;
    			dfs(r.d);
    			totalCost-=r.t;
    			totalLen-=r.L;
    			visited[r.d]=0;
    		}
    		
    	}
    }
    

    我们可以看一下这个代码,意思就是说,如果找边的时候,我们已经搜索到了终点,也就是s==N的时候,我们就直接改写minLen,然后返回到上一层,进行totalCost,totalLen和visited数组的返回工作,因为我们这次走的是这一条路,当我们返回的时候,就将这条路的终点标记全部还原,因为从这条路的起始点还可能会有其它的路,如果不把它还原的话,其它的路就被封死了,深搜就无法进行的很完全了,不能说是遍历了。

    我们对于以s为起点的边进行遍历,发现边r的花费加上之前的总花销已经超过K,总钱数了,我们就跳过这一条边,这是第一次剪枝。

    如果我们没有访问过边r的终点d时,我们就把它访问位设置为1,总路程加上r边长,总花费加上r边的过路费,然后深搜d。

    这是可以通过一些较小的数据的,但是这道题中的数据很大,而dfs中又做了很多的无用功,所以我们进行以下的剪枝:

    如果d点没有被访问过,我们就判断如果这次走到点d的时候,总路程已经超过minLen了,也就是之前找到的最短路,我们就跳过这个终点的深搜,我们直接不走这条路了。

    这个剪枝还是不够,所以我们拿空间换取时间,我们设置一个minL[110][10010]数组,minL[k][m]表示之前走到点k并且花费为m的最短长度。

    如果我们这次走到点k,并且花销为m,但是我们的路程已经大于这个最短长度了,我们就跳出这重循环,执行循环的下一次。

    因为它的意思,也就是说,我们每走过一个点,我们就进行一次比较,确保我们不花相同的钱,走更远的路,这个剪枝极为有效,直接可以过。

    代码如下:

    #include <iostream>
    #include <vector>
    #include <cstring>
    using namespace std;
    int N,K,R;
    struct Road {
    	int d,L,t;
    };
    vector < vector<Road> > G(110);
    
    int minLen;
    int minL[110][10010];
    int totalLen;	
    int totalCost;
    int visited[110];
    
    
    void dfs(int s)
    {
    	if (s==N)
    	{
    		minLen=min(minLen,totalLen);
    		return ;
    	}
    	for (int i=0;i<G[s].size();i++)
    	{
    		Road r=G[s][i];
    		if (r.t+totalCost>K)
    			continue;
    		if (!visited[r.d])
    		{
    			if (totalLen+r.L>=minLen)
    				continue;
    			if (totalLen+r.L>=minL[r.d][r.t+totalCost])
    				continue;
    			visited[r.d]=1;
    			totalLen+=r.L;
    			minL[r.d][r.t+totalCost]=totalLen;
    			totalCost+=r.t;
    			dfs(r.d);
    			totalCost-=r.t;
    			totalLen-=r.L;
    			visited[r.d]=0;
    		}
    		
    	}
    }
    
    int main()
    {
    	cin>>K>>N>>R;
    	for (int i=0;i<R;i++) {
    		int s;
    		Road r;
    		cin>>s>>r.d>>r.L>>r.t;
    		if (s!=r.d) {
    			G[s].push_back(r);
    		}
    	}
    	memset(visited,0,sizeof(visited));
    	for (int i=0;i<110;i++) {
    		for (int j=0;j<10010;j++) {
    			minL[i][j]=1<<30;
    		}
    	}
    	totalLen=0;
    	totalCost=0;
    	minLen=1<<30;
    	visited[1]=1;
    	dfs(1);
    	if (minLen<(1<<30))
    		cout<<minLen<<endl;
    	else cout<<-1<<endl;
    	return 0;
    }
  • 相关阅读:
    System.Diagnostics.Conditional 的妙用 -- 把文档放在代码中
    UGUI 特效怎样在UI上裁剪
    通过GL函数处理图片以及其它相关功能
    每次都能让人头大的 Shader -- 从整合说起
    每次都能让人头大的 Shader -- 从一次简单的功能说起
    由于闭包引起的内存泄漏
    较为激进的基础框架
    UGUI 逻辑以及实用性辅助功能
    单相机做分屏混合
    AssetBundleMaster_ReadMe_EN
  • 原文地址:https://www.cnblogs.com/xyqxyq/p/10211350.html
Copyright © 2011-2022 走看看