pku 3411 Paid Roads DFS+灵活技巧卡节点访问次数
http://poj.org/problem?id=3411
题意:
给出 n 个节点 m 条边,求从 1 到 n 的最小花费。有两种支付方式:
1> 预先在城市 Ci (必须先到过该城市)支付费用 Pi ;
2> 在终点 Bi支付费用 Ri;
思路:
这里给定的节点,边的数量都<=10爆搜没问题,关键注意一下几点:
1> 边有多条,不能用邻接矩阵计算,而要用邻接表(存在重边)。
2> Pi 始终小于等于对应的 Ri。
3> 每个点可以走多次,边也可以走多次。
这里正常的搜索写法不会重复走一个点而这里当遇到需要提前支付的路并且支付点还没有访问过就必须返回去访问支付点,这里我们每次分返回到访问过的点时,是为了增加一个可行路而返回的所以每次返回就一定会增加一个节点,所以只要访问过n次后就没必要再访问了,因为此时要么已经到达终点,要么到达不了。
View Code
#include <cstdio> #include <cstring> #include <iostream> #include <algorithm> #include <vector> #define maxn 12 using namespace std; const int inf = 0x7fffffff; int vt[maxn]; struct node { int v,r,p; int pos; node *next; }H[maxn + 10],*head[maxn]; int t,ans; int n,m; //邻接表实现建图 void insert(int u,int v,int c,int p,int r) { node *q = &H[t++]; q->v = v; q->pos = c; q->r = r; q->p = p; q->next = head[u]; head[u] = q; } void dfs(int pos,int sum) { if (pos == n) { if (sum < ans) ans = sum; return ; } node *q; for (q = head[pos]; q != NULL; q = q->next) { int v = q->v; if (vt[v] != n)//还没有访问N次 { int tmp = 0; if (vt[q->pos] != 0 && vt[q->pos] <= 10) tmp = q->p; else tmp = q->r;//寻则最优路 vt[v]++;//记住这里vt++一定要在tmp之后否则会影响。这里wa了一次 dfs(v,sum + tmp); vt[v]--; } } } int main() { //freopen("d.txt","r",stdin); int i,a,b,c,r,p; scanf("%d%d",&n,&m); t = 0; ans = inf; for (i = 0; i < m; ++i) { scanf("%d%d%d%d%d",&a,&b,&c,&p,&r); insert(a,b,c,p,r); } memset(vt,0,sizeof(vt)); dfs(1,0); if (ans != inf) printf("%d\n",ans); else printf("impossible\n"); return 0; }