题目大意:
只有一个测例,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;
}