*【HDU - 5711】Ingress(tsp旅行商问题,优先队列贪心,状压dp,floyd最短路,图论)
題干:
Brickgao, who profited from your accurate calculating last year, made a great deal of money by moving bricks. Now he became ``gay shy fool'' again and recently he bought an iphone and was deeply addicted into a cellphone game called Ingress. Now he is faced with a problem so he turns to you for help again. We make some slight modifications based on the original rules, so please draw attention to the details below.?
There are?NN?portals (indexed from 1 to?NN) around Brickgao's home, and he can get some substances called XM by hacking the portals. It's known that for each portal?ii, he can get?AiAi?XM during the first hack, and after each hack, the amount of XM he will get during the next hack will decrease by?BiBi. If the amount of XM he can get is less than or equal to zero, Brickgao can't get XM from that portal anymore. For the?ii-th portal, if?Ai=10,Bi=2Ai=10,Bi=2?and he hacks 3 times, he will get 10, 8, 6 XM during each hack.?
There are?MM?bidirectional roads between some pairs of portals and between Brickgao's home and some portals. Now he is eager to start his Ingress journey from home and finally return home, but due to the extremely hot weather, Brickgao will feel sick when you hack more than?KK?times or the distance he covers is more than?LL. So how much XM he can get at most during this journey??
?
Input
The first line contains a single integer?T(T≤20)T(T≤20), indicating the number of test cases.?
The first line of each case are four integers?N(1≤N≤16),M(0≤M≤N(N+1)2),K(1≤K≤50)N(1≤N≤16),M(0≤M≤N(N+1)2),K(1≤K≤50)?and?L(2≤L≤2000)L(2≤L≤2000).?
The second line of each case contains?NN?non-negative integers where the?ii-th denotes?Ai(Ai≤500)Ai(Ai≤500).?
The third line of each case contains?NN?non-negative integers where the?ii-th denotes?Bi(Bi≤50)Bi(Bi≤50).?
Each of next?MM?line contains 3 non-negative integers?u,v(0≤u,v≤n)u,v(0≤u,v≤n)?and?c(0≤c≤1000)c(0≤c≤1000)?, denotes that there is a road with the length of?cc?between the?uu-th and the?vv-th portal. If?uu?or?vv?equals to 0, it means Brickgao's home.?
Output
For each test case, output the case number first, then the amount of maximum XM Brickgao can get.?
Sample Input
2 1 1 3 2 5 3 0 1 1 3 6 3 5 10 7 5 2 3 1 0 1 3 0 2 1 0 3 1 1 2 2 2 3 3 1 3 4Sample Output
Case 1: 7 Case 2: 16題目大意:
n(<=16)個點(其實還有個0點為home),m(<=n^2)條雙向邊和邊權(代表兩點之間距離<=1000),K(<=50)次hack機會,最遠走L(<=2000)路程
每個點的初始點權為a[i](<=500),每個點每hack一次點權下降b[i](<=50)(變為負則當然就不選啦)
對于每個點,可以只經過不hack,也可以到這個點之后一次性hack多次。
一個人從home出發,最多hackK次,問在路程不超過L的情況下,可以獲得的最大價值。
解題報告:
因為可以只經過不hack,所以先floyd跑一邊最短路(套路了),然后不難發現可以認為:走過一個點之后不會再走回來,或者說,選擇了這個點hack了,就不會回來再hack這個點(因為還要多走距離,何必呢)(emmm其實上面說走過一個點之后不會再走回來不太合適,因為畢竟因為最短路,所以可能還是要回來的(因為這一點是最短路需要經過的點嘛))這樣我們只需要記錄狀態:走過了哪些點,當前在哪個點上,就可以跑(2^n * n)的dp了。
dp[sta][i]表示目前經過點的狀態集合為i,當前所在點的位置為 i 的最小路徑(當然要加上返程到0點的路徑)
這是典型的旅行商問題。
由此得出所有可以到達的合法點集,其狀態用2進制表示為sta。
對于每一個狀態sta,只要dp[sta][i]有一個i符合<=L,那么稱sta是合法狀態。
然后依次枚舉所有的合法sta,
對于每一個合法sta的所有點權,用貪心原則,用優先隊列選取最大的權值。
AC代碼:
#include<cstdio> #include<iostream> #include<algorithm> #include<queue> #include<map> #include<vector> #include<set> #include<string> #include<cmath> #include<cstring> #define F first #define S second #define ll long long #define pb push_back #define pm make_pair using namespace std; typedef pair<int,int> PII; const int MAX = 22; int dis[MAX][MAX],dp[1<<17][17]; int a[MAX],b[MAX]; int n,m,k,L; int up; bool ok[1<<17]; void floyd() {for(int k = 0; k<=n; k++) {for(int i = 0; i<=n; i++) {for(int j = 0; j<=n; j++) {dis[i][j] = min(dis[i][j],dis[i][k] + dis[k][j]);}}} } int tsp() {int ans = 0;for(int sta = 0; sta < up; sta++) ok[sta] = 0;memset(dp,0x3f,sizeof dp);dp[1][0]=0;for(int sta = 0; sta < up; sta++) {for(int i = 0; i<=n; i++) {if(dp[sta][i] <= L) {if(dp[sta][i] + dis[i][0] <= L) ok[sta] = 1;for(int j = 1; j<=n; j++) {dp[sta|(1<<j)][j] = min(dp[sta|1<<j][j], dp[sta][i] + dis[i][j]);}}}if(ok[sta]) {priority_queue<PII> pq;for(int i = 1; i<=n; i++) {if((sta&(1<<i) )!= 0) pq.push(pm(a[i],b[i]));}int tmp = 0;for(int i = 1; i<=k; i++) {if(pq.empty()) break;PII cur = pq.top();pq.pop();tmp += cur.F;cur.F -= cur.S;if(cur.F > 0) pq.push(pm(cur.F,cur.S)); }ans = max(ans,tmp);}}return ans; }int main() {int t,iCase=0;cin>>t;while(t--) {scanf("%d%d%d%d",&n,&m,&k,&L);up = (1<<(n+1));memset(dis,0x3f,sizeof dis);for(int i = 0; i<=n; i++) dis[i][i]=0;for(int i = 1; i<=n; i++) scanf("%d",a+i);for(int i = 1; i<=n; i++) scanf("%d",b+i);for(int q,w,e,i = 1; i<=m; i++) {scanf("%d%d%d",&q,&w,&e);if(e < dis[q][w]) dis[q][w]=dis[w][q]=e;}floyd();printf("Case %d: %d\n",++iCase,tsp());} return 0 ; }貼另一個做法:https://blog.csdn.net/qq_37025443/article/details/83513413
總結
以上是生活随笔為你收集整理的*【HDU - 5711】Ingress(tsp旅行商问题,优先队列贪心,状压dp,floyd最短路,图论)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 《黑袍纠察队》第三季祖国人演员分享幕后照
- 下一篇: 【蓝桥杯官网试题 - 真题训练】生命之树