ZOJ1027 Travelling Fee(DP+SPFA)

给一张有向无环图,边都有花费,从某点到某点走的那条路径上的那一条花费最多的边可以省掉,问从起点到终点的最少花费的多少,

往DP想的话,就可以写出这个状态dp[u][mx],表示到达u点已经省掉的花费为mx的最少花费。

用SPFA更新转移方程。。或者理解成队列+我为人人的转移。。其实这题这样子也能解有环图。

看了别人博客,发现还有三种解法:

  1. 枚举每一条边作为省掉的边,n次SPFA。这方法简洁,可惜想不出= =
  2. 跑Dijkstra,根据记录到每一点时的最长边更新,正确性不懂。。
  3. Floyd+DP:加个维度,dpk[0\1][u][v],第一维1和0分别表示省和没省最长边的最少花费,dp[1]的转移就是dp[1][u][v]=min(dp[0][u][k]+dp[1][k][v],dp[1][u][k]+dp[0][k][v]),初始dp[1][i][j]=0(<i,j>∈E),好厉害。。
 1 #include<cstdio>
 2 #include<cstring>
 3 #include<iostream>
 4 #include<queue>
 5 #include<string>
 6 #include<algorithm>
 7 using namespace std;
 8 #define INF (1<<29)
 9 int n,G[222][222];
10 int d[222][10001];
11 bool vis[222][10001];
12 struct Node{
13     int u,mx;
14     Node(int _u,int _mx):u(_u),mx(_mx){}
15 };
16 void SPFA(int vs){
17     for(int i=0; i<n; ++i){
18         for(int j=0; j<10001; ++j) d[i][j]=INF;
19     }
20     d[vs][0]=0;
21     memset(vis,0,sizeof(vis));
22     vis[vs][0]=1;
23     queue<Node> que;
24     que.push(Node(vs,0));
25     while(!que.empty()){
26         Node nd=que.front(); que.pop();
27         int u=nd.u,mx=nd.mx;
28         for(int v=0; v<n; ++v){
29             if(G[u][v]==INF) continue;
30             if(G[u][v]>mx && d[v][G[u][v]]>d[u][mx]+mx){
31                 d[v][G[u][v]]=d[u][mx]+mx;
32                 if(!vis[v][G[u][v]]){
33                     vis[v][G[u][v]]=1;
34                     que.push(Node(v,G[u][v]));
35                 }
36             }
37             if(d[v][mx]>d[u][mx]+G[u][v]){
38                 d[v][mx]=d[u][mx]+G[u][v];
39                 if(!vis[v][mx]){
40                     vis[v][mx]=1;
41                     que.push(Node(v,mx));
42                 }
43             }
44         }
45         vis[u][mx]=0;
46     }
47 }
48 int main(){
49     string name[222],x[111],y[111],vs,vt;
50     int m,z[111];
51     while(cin>>vs>>vt){
52         n=0;
53         scanf("%d",&m);
54         for(int i=0; i<m; ++i){
55             cin>>x[i]>>y[i]>>z[i];
56             name[n++]=x[i]; name[n++]=y[i];
57         }
58         sort(name,name+n);
59         n=unique(name,name+n)-name;
60         for(int i=0; i<n; ++i){
61             for(int j=0; j<n; ++j) G[i][j]=INF;
62         }
63         for(int i=0; i<m; ++i){
64             int u=lower_bound(name,name+n,x[i])-name,v=lower_bound(name,name+n,y[i])-name;
65             G[u][v]=z[i];
66         }
67         SPFA(lower_bound(name,name+n,vs)-name);
68         int tv=lower_bound(name,name+n,vt)-name;
69         int res=INF;
70         for(int i=0; i<10001; ++i) res=min(res,d[tv][i]);
71         printf("%d\n",res);
72     }
73     return 0;
74 }
时间: 2024-10-24 17:52:17

ZOJ1027 Travelling Fee(DP+SPFA)的相关文章

UVA 10497 - Sweet Child Makes Trouble(DP+高精度)

题目链接:10497 - Sweet Child Makes Trouble 题意:n个物品,原来物品属于一个地方,现在要把物品重新放回去,问能放几种使得每个物品都与原来位置不同 思路:递推,一开始随便搞了个二维状态,dp[i][j]表示i个物品,有j个位置不同,那么dp[n][n]就是答案,递推式为: dp[i][j] = 1 (j == 0) dp[i][j] = (j - 1) * dp[i - 1][j - 1] + dp[i - 1][j] + (i - j + 1) * dp[i -

UVA 10641 - Barisal Stadium(DP + 几何)

题目链接:10641 - Barisal Stadium 题意:逆时针给定n个点,在给m个灯,每个灯有一个花费,要求最小花费使得所有边能被灯照到 思路:用向量叉积判断向量的顺逆时针关系,从而预处理出每个灯能照到的边,然后由于n个点是环的,所以可以直接扩大两倍,dp时候去枚举起点即可 状态为dp[i]表示现在照到i条边之前的边全部照亮需要的最小花费 代码: #include <stdio.h> #include <string.h> const double eps = 1e-6;

HDU 2577 How to Type(dp题)

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=2577 解题报告:有一个长度在100以内的字符串,并且这个字符串只有大写和小写字母组成,现在要把这些字符串用键盘输入到电脑中,一开始的时候大写锁定是关闭的,并且要求结束的时候也是关闭的,然后让你求输入这些字符串最少需要按多少次键盘(包括Cap Lock键和Shift键) 一个典型的dp题,定义一个一维数组就够了,然后dp[i]的含义的输入到第i个字符时需要按键的最少次数.然后递推公式如下: dp[i]

hdu 4945 2048 (dp+组合数)

2048 Time Limit: 3000/1500 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others) Total Submission(s): 840    Accepted Submission(s): 199 Problem Description Teacher Mai is addicted to game 2048. But finally he finds it's too hard to get 2048.

ZOJ 3631 Watashi&#39;s BG(dp+dfs)

题意:一共要吃n顿饭 公款m元 如果公款大于等于饭局所需费用 就全用公款 如果小于就自费 求最后能用的公款为多少 思路: dfs(i - 1, val + dp[i]); dfs(i - 1, val); #include <stdio.h> #include <string.h> #include <stdlib.h> #include <algorithm> using namespace std; int dp[50]; int n, m; int a

UVA10759 - Dice Throwing(dp+gcd)

UVA10759 - Dice Throwing(dp+gcd) 题目链接 题目大意:n个色子,求n个色子之和不小于x的概率. 解题思路:因为可以将题目转化成求n个色子和小于x的数目,最后再6^n减去就这个数目就是大于等于x的数目了.因为n最大就24,这样还是可以用long long来存放,最后输出要求的是分数形式,将分子分母用gcd约分一下输出即可. 代码: #include <cstdio> #include <cstring> typedef long long ll; co

UVA 1543 - Telescope(dp+几何)

题目链接:1543 - Telescope 题意:按顺序给定圆周上一些点,问用选一些点组成m边形面积的最大值. 思路:dp,dp[i][j][k] 表示第一个点为i,最后一个点为j,当前选择k的最大值,因为多选一个点,会多的面积为他和第一个点和最后一个点构成的三角形面积,然后利用海伦公式求面积,状态转移为:dp[i][j][x] = max(dp[i][j][x], dp[i - 1][j][k] + s); 代码: #include <stdio.h> #include <string

hdu 1025 Constructing Roads In JGShining&#39;s Kingdom(DP + 二分)

此博客为转发 Constructing Roads In JGShining's Kingdom Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others) Problem Description JGShining's kingdom consists of 2n(n is no more than 500,000) small cities which are located in t

HDU 1058 Humble Numbers(DP,数)

题意  所有只能被2,3,5,7这4个素数整除的数称为Humble Number  输入n  输出第n个Humble Number 1是第一个humble number  对于一个Humble Number  a  有2*a,3*a,5*a,7*a都是Humble Number  可以以1为基数  依次展开即可得到一定范围内的Humble Number 用i,j,k,l分别记录 2,3,5,7分别乘到了第几个Humble Number  当前在计算第cnt个Humble Number  那么有