Question: given some cities, starting from 1 and traveling back to 1, because the cost may not be enough, I chose some cities to work. Before working, I had to spend d to buy a certificate and my salary was c. The selected city must work once and only once.
During the competition, I got stuck for a long time. At that time, my teammates wrote the code using SPFA + status DP + stack, mainly because they were wrong.
At that time, C and D were merged. In fact, it was wrong, because the first thing is to buy a license before you can work, or else you will not be able to get the salary.
That is, you must first determine that you have enough money to buy a license D before you can get the salary.
The best practice is to use Floyd to pre-process at least n ^ 3, and then the DP, h * 2 ^ h, 4 S + states, which is very inefficient.
Queue and stack acceleration are available
[Cpp]
# Include <iostream>
# Include <cstdio>
# Include <map>
# Include <cstring>
# Define inf 1 <28
# Define N 105
# Define Min (a, B) (a) <(B )? (A) (B ))
# Define Max (a, B) (a)> (B )? (A) (B ))
Using namespace std;
Int n, m, money, h;
Int path [N] [N];
Int dp [20] [1 <16];
Int work [20], c [20], d [20];
Int main (){
Int t;
Scanf ("% d", & t );
While (t --){
Scanf ("% d", & n, & m, & money );
For (int I = 0; I <n; I ++ ){
For (int j = 0; j <n; j ++)
Path [I] [j] = inf;
Path [I] [I] = 0;
}
For (int I = 0; I <m; I ++ ){
Int u, v, w;
Scanf ("% d", & u, & v, & w );
U --; v --;
Path [u] [v] = Min (path [u] [v], w );
Path [v] [u] = path [u] [v];
}
// Floyd preprocessing
For (int k = 0; k <n; k ++)
For (int I = 0; I <n; I ++)
For (int j = 0; j <n; j ++)
If (I! = K & I! = J & j! = K)
Path [I] [j] = Min (path [I] [k] + path [k] [j], path [I] [j]);
Scanf ("% d", & h );
Int pos =-1;
For (int I = 0; I Scanf ("% d", & work [I], & c [I], & d [I]);
Work [I] --;
If (work [I] = 0) pos = I; // It indicates that the starting point 1 is included.
}
// If not included, we add redundancy points to facilitate subsequent processing. Both c and d are 0.
If (pos =-1 ){
Work [h] = 0; c [h] = 0; d [h] = 0;
Pos = h ++;
}
Memset (dp,-1, sizeof (dp ));
If (money-d [pos]> = 0) dp [pos] [1 <pos] = money-d [pos] + c [pos]; dp [pos] [0] = money;
For (int I = 0; I <(1 For (int j = 0; j If (dp [j] [I] =-1) continue;
For (int k = 0; k If (k = j | (1 <k) & I) continue;
// The money is enough to move between two cities and the money is enough to buy a license
If (dp [j] [I]> = path [work [j] [work [k] + d [k])
Dp [k] [I | (1 <k)] = Max (dp [k] [I | (1 <k)], dp [j] [I]-path [work [j] [work [k]-d [k] + c [k]);
}
}
}
Bool ans = false;
For (int I = 0; I // Finally, determine whether the start point can be returned.
If (dp [I] [(1 Ans = true;
Break;
}
Puts (ans? "YES": "NO ");
}
Return 0;
}