GYM101635E Ingredients
题目链接:https://vjudge.net/problem/Gym-101635E
题目大意:
给定一个有 \(N\) 条边的有向无环图(有多个起点),每条边都有其费用和收益,现要从一个或多个起点出发,以某一个或多个点为终点(一个点不能多次作为终点;如果有多个方案能到达同一个点,则选择总费用最少的),问在使得总费用不超过 \(B\) 的大前提下,能得到的最大收益(如果有多个得到最大收益的方法,则选择使得费用最少的)。输出最大收益及其对应的总费用。
(建议仔细地读一下 \(Important Notes\))
知识点: DP、最短路
解题思路:
先用 \(Dijkstra\) 跑出从各个起点到各个点的最小费用及其对应的收益(如果有多个费用最小的方案,则选择收益最大的那个),再用 \(dp\) 计算出在各个总费用下所能得到的最大收益。
AC代码:
1 #include <bits/stdc++.h> 2 using namespace std; 3 const int maxm = 1000000+5, maxn = 10000+5, inf=0x3f3f3f3f; 4 5 struct Edge{ 6 int to,nxt,cost,prestige; 7 }edge[maxm]; 8 int head[maxm],tot; 9 void init(){ 10 memset(head,-1,sizeof(head)); 11 tot=0; 12 } 13 void addedge(int u,int v,int cost,int pres){ 14 edge[tot].to=v; 15 edge[tot].nxt=head[u]; 16 edge[tot].prestige=pres; 17 edge[tot].cost=cost; 18 head[u]=tot++; 19 } 20 21 int min_cost[maxn],max_pres[maxn]; 22 bool noroot[maxn]; 23 map<string,int> ind; 24 25 void dijkstra(int s){ 26 queue<int> que; 27 que.push(s); 28 min_cost[s]=max_pres[s]=0; 29 while(!que.empty()){ 30 int v=que.front(); 31 que.pop(); 32 for(int i=head[v];i!=-1;i=edge[i].nxt){ 33 int to=edge[i].to; 34 if(min_cost[to]>min_cost[v]+edge[i].cost){ 35 min_cost[to]=min_cost[v]+edge[i].cost; 36 max_pres[to]=max_pres[v]+edge[i].prestige; 37 que.push(to); 38 } 39 else if(min_cost[to]==min_cost[v]+edge[i].cost&&max_pres[to]<max_pres[v]+edge[i].prestige){ 40 max_pres[to]=max_pres[v]+edge[i].prestige; 41 que.push(to); 42 } 43 } 44 } 45 } 46 int dp[maxn]; 47 int main(){ 48 std::ios::sync_with_stdio(false); //如果没有加速输入输出的话会T 49 int B,N,cos,pre,u,v; 50 int cnt=1; 51 string to,from,tmp; 52 cin>>B>>N; 53 init(); 54 for(int i=0;i<N;i++){ 55 cin>>to>>from>>tmp>>cos>>pre; 56 if(!ind[to]) 57 ind[to]=cnt++; 58 v=ind[to]; 59 if(!ind[from]) 60 ind[from]=cnt++; 61 u=ind[from]; 62 addedge(u,v,cos,pre); 63 noroot[v]=true; 64 } 65 for(int i=1;i<cnt;i++) 66 min_cost[i]=inf,max_pres[i]=0; 67 for(int i=1;i<cnt;i++){ 68 if(!noroot[i]) 69 dijkstra(i); 70 } 71 dp[0]=0; 72 for(int i=1;i<cnt;i++){ 73 for(int j=B;j>=min_cost[i];j--) 74 dp[j]=max(dp[j],dp[j-min_cost[i]]+max_pres[i]); 75 } 76 int ans1=0,ans2=0; 77 for(int i=0;i<=B;i++){ 78 if(dp[i]>ans1) 79 ans1=dp[i],ans2=i; 80 } 81 cout<<ans1<<endl; 82 cout<<ans2<<endl; 83 84 return 0; 85 }
“这些年我一直提醒自己一件事情,千万不要自己感动自己。大部分人看似的努力,不过是愚蠢导致的。什么熬夜看书到天亮,连续几天只睡几小时,多久没放假了,如果这些东西也值得夸耀,那么富士康流水线上任何一个人都比你努力多了。人难免天生有自怜的情绪,唯有时刻保持清醒,才能看清真正的价值在哪里。”