程设2021期末题F:交易市场
原题:http://cxsjsx.openjudge.cn/2021finalpractise/F/
描述
市场里面一共有n种物品,有m种交易途径,每个交易途径可以由(x,y,z)表示,意思是可以用第x种物品换成第y种物品,并且得到z元的收益(z均大于0)。最开始你只有第一种物品,请问最多可以赚取多少收益。
输入
第一行两个正整数n和m(n ≤ 1000,m ≤ 4000)
接下来m行,每行三个正整数x, y, z,意思是可以用第x种物品换成第y种物品,并且得到z元的收益。(1 ≤ x,y ≤ n, 1 ≤ z ≤ 100)
输出
一个整数表示最大收益,如果可以赚取无穷多的收益则输出1000000000
样例输入
3 3 1 2 2 2 3 3 1 3 4
样例输出
5
解法
这道题用动态规划可以做。采用我为人人型递推。
dp[i]表示最后是第i种物品时的最大价值,无穷多的收益等于出现环,要判断环所以要记录路径。扫描到每个转换关系时更新目标节点的dp。
注意这道题还有广搜的思想,动态规划的节点顺序是用队列来决定,有的节点根本到不了就不用考虑它的转换关系。有的节点增加了转换关系就应该重新计算。
代码如下:
1 #include <iostream> 2 #include <vector> 3 #include <map> 4 #include <set> 5 #include <cstring> 6 #include <algorithm> 7 #include <queue> 8 #define INF 1000000000 9 using namespace std; 10 struct exchangeTo { 11 int target; 12 int p; 13 exchangeTo(int a, int b) :target(a), p(b) {} 14 }; 15 struct path { 16 int pre; 17 int val; 18 }dp[1005]; 19 map<int, vector<exchangeTo> >tables; 20 bool inPath(int n, int k) { 21 while (k != -1) { 22 if (n == k) 23 return true; 24 k = dp[k].pre; 25 } 26 return false; 27 } 28 int main() { 29 memset(dp, -1, sizeof(dp)); 30 int n, m; 31 cin >> n >> m; 32 for (int i = 0; i < m; i++) { 33 int x, y, z; 34 cin >> x >> y >> z; 35 tables[x].push_back(exchangeTo(y, z)); 36 } 37 dp[1].val = 0, dp[1].pre = 0; 38 bool done = false; 39 int result = 0; 40 queue<int>myqueues; 41 myqueues.push(1); 42 while (!myqueues.empty()) { 43 int top = myqueues.front(); 44 myqueues.pop(); 45 if (!tables[top].empty()) { 46 vector<exchangeTo>::iterator ii; 47 for (ii = tables[top].begin(); ii != tables[top].end(); ii++) { 48 if (inPath(ii->target, top)) 49 { 50 result = INF; 51 done = true; 52 break; 53 } 54 if (dp[top].val + ii->p > dp[ii->target].val) { 55 dp[ii->target].val = dp[top].val + ii->p; 56 dp[ii->target].pre = top; 57 myqueues.push(ii->target);//注意这里的更新 58 } 59 result = max(result, dp[ii->target].val); 60 } 61 if (done)break; 62 } 63 } 64 cout << result << endl; 65 return 0; 66 }

浙公网安备 33010602011771号