POJ 1724 ROADS

题目大意:

        只有一个测例,N个城编号1 ~ N(2 ≤ N ≤ 100),共有R条单向边(1 ≤ R ≤ 10,000),会给出每条边的信息S、D、L、T,其中S和D表示边的起点和终点城市编号(1 ≤ S, D ≤ N),L是边的长度(1 ≤ L ≤ 100),T是过路费(0 ≤ T ≤ 100),不同地方边可能拥有相同的起点和终点,现要从1号城市走到N号城市,一开始手里只有费用K(0 ≤ K ≤ 10,000),现要求输出可能的最短路径长度(总路费不能超过K),如果不存在输出-1。

题目链接

DFS+DP优化+剪枝

注释代码:

/*                                  
 * Problem ID : POJ 1724 ROADS
 * Author     : Lirx.t.Una                                  
 * Language   : C++                      
 * Run Time   : 79 ms                                  
 * Run Memory : 2364 KB                                  
*/ 

#include <algorithm>
#include <iostream>
#include <cstdio>

//路径长度的无穷大(大于 100 × 100)
#define	INF		20000

//城市最大数量
#define	MAXN		100
//边的最大数量
#define	MAXR		10000
//路途最大开销100 × 100
#define	MAXC		10000

using namespace std;

struct	Arc { char v, l, c; };

Arc		arc[MAXR + 1];
short	head[MAXN + 1];
short	nxt[MAXR + 1];
int		e;

bool	vis[MAXN + 1];
//dp[u][c]表示到达点u并且消耗的费用刚好是c的时候所走的当前最短路径长度
short	dp[MAXN + 1][MAXC + 1000];

int		cur_len;//深搜时当前路径长度
int		cur_cost;//深搜时当前所消耗费用
int		ans = INF;//最终答案,最短路径

int		k, n;//起始费用和城市数量

void
addarc( int u, int v, int l, int c ) {

	arc[e].v = v;
	arc[e].l = l;
	arc[e].c = c;

	nxt[e]  = head[u];
	head[u] = e++;
}

void
dfs(int u) {

	int		v;//临时点
	int		i;

	int		tmp_c;//临时费用变量
	int		tmp_l;//临时路径长度变量

	if ( u == n ) {//已经搜到目标
	
		ans = min( ans, cur_len );//更新答案
		return ;
	}

	for ( i = head[u]; i; i = nxt[i] ) {//往下一层探索
	
		if ( !vis[ v = arc[i].v ] ) {
		
			if ( ( tmp_c = cur_cost + arc[i].c ) > k ) continue;//剪枝1,超过起始费用
			if ( ( tmp_l = cur_len + arc[i].l ) >= ans ||//剪枝2,超过之前所搜的最优答案
				 tmp_l >= dp[v][tmp_c] ) continue;//剪枝3,超过之前到达v点并且话费为tmp_c的最短路径长度
			//三种剪枝条件由弱到强

			cur_len  		= tmp_l;//更新
			cur_cost 		= tmp_c;
			dp[v][cur_cost] = cur_len;

			vis[v] = true;
			dfs(v);//向下搜索
			vis[v] = false;//还原现场,继续本层的搜索

			cur_len  -= arc[i].l;
			cur_cost -= arc[i].c;
		}
	}
}

int
main() {

	int		r;//边数
	int		u, v, l, c;//临时点、临时边长、临时费用变量

	int		i, j;


	scanf("%d%d%d", &k, &n, &r);
	for ( i = 1; i <= n; i++ )//初始化DP
		for ( j = 0; j < MAXC; j++ )
			dp[i][j] = INF;

	e = 1;
	while ( r-- ) {
	
		scanf("%d%d%d%d", &u, &v, &l, &c);
		if ( u != v ) addarc( u, v, l, c );//避免坑爹的输入
	}

	vis[1] = true;
	dfs(1);

	if ( ans < INF ) printf("%d\n", ans);
	else puts("-1");

	return 0;
}

无注释代码:

#include <algorithm>
#include <iostream>
#include <cstdio>

#define	INF		20000

#define	MAXN		100
#define	MAXR		10000
#define	MAXC		10000

using namespace std;

struct	Arc { char v, l, c; };

Arc		arc[MAXR + 1];
short	head[MAXN + 1];
short	nxt[MAXR + 1];
int		e;

bool	vis[MAXN + 1];
short	dp[MAXN + 1][MAXC + 1000];

int		cur_len;
int		cur_cost;
int		ans = INF;

int		k, n;

void
addarc( int u, int v, int l, int c ) {

	arc[e].v = v;
	arc[e].l = l;
	arc[e].c = c;

	nxt[e]  = head[u];
	head[u] = e++;
}

void
dfs(int u) {

	int		v;
	int		i;

	int		tmp_c;
	int		tmp_l;

	if ( u == n ) {
	
		ans = min( ans, cur_len );
		return ;
	}

	for ( i = head[u]; i; i = nxt[i] ) {
	
		if ( !vis[ v = arc[i].v ] ) {
		
			if ( ( tmp_c = cur_cost + arc[i].c ) > k ) continue;
			if ( ( tmp_l = cur_len + arc[i].l ) >= ans ||
				 tmp_l >= dp[v][tmp_c] ) continue;

			cur_len  		= tmp_l;
			cur_cost 		= tmp_c;
			dp[v][cur_cost] = cur_len;

			vis[v] = true;
			dfs(v);
			vis[v] = false;

			cur_len  -= arc[i].l;
			cur_cost -= arc[i].c;
		}
	}
}

int
main() {

	int		r;
	int		u, v, l, c;

	int		i, j;


	scanf("%d%d%d", &k, &n, &r);
	for ( i = 1; i <= n; i++ )
		for ( j = 0; j < MAXC; j++ )
			dp[i][j] = INF;

	e = 1;
	while ( r-- ) {
	
		scanf("%d%d%d%d", &u, &v, &l, &c);
		if ( u != v ) addarc( u, v, l, c );
	}

	vis[1] = true;
	dfs(1);

	if ( ans < INF ) printf("%d\n", ans);
	else puts("-1");

	return 0;
}

BFS+堆优化:

注释代码:

/*                                  
 * Problem ID : POJ 1724 ROADS
 * Author     : Lirx.t.Una                                  
 * Language   : C++                      
 * Run Time   : 16 ms                                  
 * Run Memory : 676 KB                                  
*/ 

#include <iostream>
#include <cstdio>
#include <queue>

#define	MAXN	100
#define	MAXR	10000

using namespace std;

struct	Node {//广搜队列结点,同时也是邻接表中的边
	
	short	l;//边长/到当前点p的路径长度
	short	c;//边的费用/到当前点p所消耗的所有费用
	short	p;//点编号
	
	Node(void) {}
	
	Node( int pp, int ll, int cc ) :
	p(pp), l(ll), c(cc) {}
	
	bool//小顶堆
	operator<(const Node &oth)
	const {
		
		return l > oth.l;
	}
};

Node	arc[MAXR + 1];
short	head[MAXN + 1];
short	nxt[MAXR + 1];
int		e;

int		k, n;

priority_queue<Node>	heap;

void
addarc( int u, int v, int l, int c ) {
	
	arc[e].p = v;
	arc[e].l = l;
	arc[e].c = c;
	
	nxt[e]  = head[u];
	head[u] = e++;
}

int
bfs(void) {
	
	Node	node;//当前点
	int		i;
	
	heap.push( Node( 1, 0, 0 ) );
	
	while ( !heap.empty() ) {
		
		node = heap.top();
		if ( n == node.p ) return node.l;//搜索成功
		heap.pop();
		
		for ( i = head[node.p]; i; i = nxt[i] )	
			if ( node.c + arc[i].c <= k )//小剪枝
				//不能使用vist标记,因为不同点顺序会导致路径长度不同
				heap.push( Node( arc[i].p, node.l + arc[i].l, node.c + arc[i].c ) );
	}
	
	return -1;
}

int
main() {
	
	int		r;
	int		u, v, l, c;
	
	scanf("%d%d%d", &k, &n, &r);
	
	e = 1;
	while ( r-- ) {
		
		scanf("%d%d%d%d", &u, &v, &l, &c);
		addarc( u, v, l, c );
	}
	
	printf("%d\n", bfs());
	
	return 0;
}
无注释代码:

#include <iostream>
#include <cstdio>
#include <queue>

#define	MAXN	100
#define	MAXR	10000

using namespace std;

struct	Node {

	short	l;
	short	c;
	short	p;

	Node(void) {}

	Node( int pp, int ll, int cc ) :
		p(pp), l(ll), c(cc) {}

	bool
	operator<(const Node &oth)
	const {
	
		return l > oth.l;
	}
};

Node	arc[MAXR + 1];
short	head[MAXN + 1];
short	nxt[MAXR + 1];
int		e;

int		k, n;

priority_queue<Node>	heap;

void
addarc( int u, int v, int l, int c ) {

	arc[e].p = v;
	arc[e].l = l;
	arc[e].c = c;

	nxt[e]  = head[u];
	head[u] = e++;
}

int
bfs(void) {

	Node	node;
	int		i;

	heap.push( Node( 1, 0, 0 ) );

	while ( !heap.empty() ) {
	
		node = heap.top();
		if ( n == node.p ) return node.l;
		heap.pop();

		for ( i = head[node.p]; i; i = nxt[i] )	
			if ( node.c + arc[i].c <= k )
				heap.push( Node( arc[i].p, node.l + arc[i].l, node.c + arc[i].c ) );
	}

	return -1;
}

int
main() {

	int		r;
	int		u, v, l, c;

	scanf("%d%d%d", &k, &n, &r);

	e = 1;
	while ( r-- ) {
	
		scanf("%d%d%d%d", &u, &v, &l, &c);
		addarc( u, v, l, c );
	}

	printf("%d\n", bfs());

	return 0;
}

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值