Poj 1724 Roads(DFS 可行性剪枝 最优性剪枝 向量)

#include<iostream>
#include<cstdio>
#include<string>
#include<cstring>
#include<algorithm>
#include<cstdlib>
#include<vector>
using namespace std;

struct Roads
{
    int d;
    int l;
    int t;
};

vector<Roads> city[105];    //定义向量,相当于一个二维数组,其中第一维的长度无限大,第二维的长度是105,数组中的各个元素是之前定义的Roads结构体

int K,N,R;
int totallen,totalcost,minlen;
int minn[105][10005];    //minn[i][j]表示到达i城市且花费了j时所走的最小路程 ,用于下面每走到一个城市都可以进行剪枝
int visited[105];       //由于本题是求最短路径长度,而若是走的过程中,对一个城市走了不止一遍,那么肯定不再是最短路径长度,所以每一个城市都不可以重复走

void dfs( int c )
{
    if( c == N )   //走到了终点
        {
              minlen = min( minlen , totallen );  //结束递归之前,先更新minlen的值
           return ;
        }
    int rnum = city[c].size();
    for( int i = 0 ; i < rnum ; ++i )   //遍历c城市所能走的所有路
     {
          if( visited[city[c][i].d] || totalcost + city[c][i].t > K )   //可行性剪枝
            continue;
         if( totallen + city[c][i].l >= minlen || totallen + city[c][i].l >= minn[city[c][i].d][totalcost + city[c][i].t] )  //最优性剪枝    
             continue;
         totalcost += city[c][i].t;
         totallen += city[c][i].l;
         minn[city[c][i].d][totalcost] = totallen;
         visited[city[c][i].d] = 1;   //更新状态
         dfs(city[c][i].d);
         totallen -=  city[c][i].l;
         totalcost -= city[c][i].t;
         visited[city[c][i].d] = 0;   //还原状态
      }    
}


int main()
{
   freopen( "E:\\in.txt", "r" , stdin );
   cin >> K;   //总共的钱
   cin >> N >> R;
   for(int i = 0; i < R ; ++i)   //构建图(连接表)
      {
            int s;
            cin>>s;
            Roads r;
            cin>>r.d>>r.l>>r.t;
            city[s].push_back(r);
      }
   totalcost = 0;  //初始化
   totallen = 0;
   minlen = 1 << 30;
   for(int i = 0 ; i < 105 ; ++i)
       for(int j = 0 ; j < 10005 ; ++j)
            minn[i][j] = 1 << 30;
   memset(visited,0,sizeof(visited));
   dfs(1);    //深搜开始
   if(minlen == 1 << 30)    //minlen的值没有被改变 说明并没有找到合适的路
      cout << "-1" << endl;
   else
      cout << minlen << endl;
   return 0;   
}



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值