这道题目如果数据很小的话。我们通过这个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;
}

POJ-1724 深搜剪枝的更多相关文章

  1. POJ 2531 深搜剪枝

    题意:全局最大割. 分析:有相应的算法,数据量很小,可以枚举源点,汇点,最大流. 这里用DFS,状态定义:分成两个集合,刚开始S集合全部点,然后一个一个放,这是一个回溯的过程. 没剪枝也过了. 剪枝技 ...

  2. Hdu3812-Sea Sky(深搜+剪枝)

    Sea and Sky are the most favorite things of iSea, even when he was a small child.  Suzi once wrote: ...

  3. 深搜+剪枝 POJ 1724 ROADS

    POJ 1724 ROADS Time Limit: 1000MS   Memory Limit: 65536K Total Submissions: 12766   Accepted: 4722 D ...

  4. poj1190 生日蛋糕(深搜+剪枝)

    题目链接:poj1190 生日蛋糕 解题思路: 深搜,枚举:每一层可能的高度和半径 确定搜索范围:底层蛋糕的最大可能半径和最大可能高度 搜索顺序:从底层往上搭蛋糕,在同一层尝试时,半径和高度都是从大到 ...

  5. UVA 10160 Servicing Stations(深搜 + 剪枝)

    Problem D: Servicing stations A company offers personal computers for sale in N towns (3 <= N < ...

  6. ACM 海贼王之伟大航路(深搜剪枝)

    "我是要成为海贼王的男人!" 路飞他们伟大航路行程的起点是罗格镇,终点是拉夫德鲁(那里藏匿着"唯一的大秘宝"--ONE PIECE).而航程中间,则是各式各样的 ...

  7. hdu 1518 Square(深搜+剪枝)

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1518 题目大意:根据题目所给的几条边,来判断是否能构成正方形,一个很好的深搜应用,注意剪枝,以防超时! ...

  8. 一本通例题-生日蛋糕——题解<超强深搜剪枝,从无限到有限>

    题目传送 显然是道深搜题.由于蛋糕上表面在最底层的半径确认后就确认了,所以搜索时的面积着重看侧面积. 找维度/搜索面临状态/对象:当前体积v,当前外表面面积s,各层的半径r[],各层的高度h[]. 可 ...

  9. 模拟赛T5 : domino ——深搜+剪枝+位运算优化

    这道题涉及的知识点有点多... 所以还是比较有意思的. domino 描述 迈克生日那天收到一张 N*N 的表格(1 ≤ N ≤ 2000),每个格子里有一个非 负整数(整数范围 0~1000),迈克 ...

随机推荐

  1. 【Codeforces自我陶醉水题篇~】(差17C code....)

    Codeforces17A 题意: 有一种素数会等于两个相邻的素数相加 如果在2~n的范围内有至少k个这样的素数,就YES,否则就NO; 思路: 采用直接打表,后面判断一下就好了.那个预处理素数表还是 ...

  2. bzoj 1477: 青蛙的约会【exgcd】

    列出式子是\( mx+s1\equiv nx+s2(mod L) (m-n)x+Ly=s2-s1 \),注意如果n-m<0的话,就把ac都乘-1变成正数,然后exgcd求解,最后注意x为负的话要 ...

  3. JAVA实训总结:继承-——子类创建对象原理

    继承关键字:extends Java只允许单继承存在 不可以被继承的东西: 1.private成员 体现了java的封装特点,外部类只允许set()get()方法调用,若无set()方法,则类创建的对 ...

  4. 跟我一起玩Win32开发(10):绘图(C)

    今天我们来欣赏一下用于填充图形的函数,当然我不会逐个去介绍,因为我们参考MSDN直接套参数就可以了. SetDCBrushColor函数有必要扯一下,它的声明如下: COLORREF SetDCBru ...

  5. 项目上线后出现Bug,该如何处理?

    项目在上线之后又出现了Bug,这让很多测试人员和开发人员头痛.但很多时候线上Bug普遍地存在,不可避免. 任何项目都存在未发现 Bug  和 已发现 Bug  两种情况,不存在没有 Bug的情况. 即 ...

  6. Python %s和%r的区别

    %s 用str()方法处理对象 %r 用rper()方法处理对象,打印时能够重现它所代表的对象(rper() unambiguously recreate the object it represen ...

  7. python之重写父类方法

    #修改父类的方法#重写父类的方法的目的是为了给他扩展功能,父类的方法已经不能满足需求#核心思想就一句话,先调用一下你要重写的父类方法,class Coon(object): #基本类 def __in ...

  8. 使用PreparedStatement接口

  9. 523 Continuous Subarray Sum 非负数组中找到和为K的倍数的连续子数组

    非负数组中找到和为K的倍数的连续子数组 详见:https://leetcode.com/problems/continuous-subarray-sum/description/ Java实现: 方法 ...

  10. 【译】建立属于你的个人高效系统——效率专家 Mike Vardy 教你如何设置一个简单的个人高效系统

    原文:http://mux.baidu.com/?p=5300 百度MUX 已经有太多的高效系统供人使用,而对于那些刚刚开始,想寻求更好方法完成他们任务,项目,目标的人来说,要做一个高效系统却是相当艰 ...