Ingress
Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 102400/65535 K (Java/Others)
Total Submission(s): 440 Accepted Submission(s): 205
Problem Description
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 portals (indexed from 1 to ) around Brickgao's home, and he can get some substances called XM by hacking the portals. It's known that for each portal , he can get XM during the first hack, and after each hack, the amount of XM he will get during the next hack will decrease by . 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 -th portal, if and he hacks 3 times, he will get 10, 8, 6 XM during each hack.
There are 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 times or the distance he covers is more than . So how much XM he can get at most during this journey?
Input
The first line contains a single integer , indicating the number of test cases.
The first line of each case are four integers and .
The second line of each case contains non-negative integers where the -th denotes .
The third line of each case contains non-negative integers where the -th denotes .
Each of next line contains 3 non-negative integers and , denotes that there is a road with the length of between the -th and the -th portal. If or 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 4
Sample Output
#include<stdio.h>
#include <algorithm>
#include<iostream>
#include<string.h>
#include<vector>
#include<stdlib.h>
#include<math.h>
#include<queue>
#include<deque>
#include<ctype.h>
#include<map>
#include<set>
#include<stack>
#include<string>
#include<algorithm>
#define INF 0x3f3f3f3f
#define FAST_IO ios::sync_with_stdio(false)
const double PI = acos(-1.0);
const double eps = 1e-6;
const int MAX=1e5+10;
const int mod=1e9+7;
typedef long long ll;
using namespace std;
#define gcd(a,b) __gcd(a,b)
inline ll lcm(ll a,ll b){return a/gcd(a,b)*b;}
inline ll qpow(ll a,ll b){ll r=1,t=a; while(b){if(b&1)r=(r*t)%mod;b>>=1;t=(t*t)%mod;}return r;}
inline ll inv1(ll b){return qpow(b,mod-2);}
//inline ll exgcd(ll a,ll b,ll &x,ll &y){if(!b){x=1;y=0;return a;}ll r=exgcd(b,a%b,y,x);y-=(a/b)*x;return r;}
inline ll read(){ll x=0,f=1;char c=getchar();for(;!isdigit(c);c=getchar()) if(c=='-') f=-1;for(;isdigit(c);c=getchar()) x=x*10+c-'0';return x*f;}
//freopen( "in.txt" , "r" , stdin );
//freopen( "data.txt" , "w" , stdout );
int a[25],b[25];
int d[25][25];
int dp[1<<17][25];
typedef pair<int,int>P;
void floyd(int n)
{
for(int k=0;k<=n;k++)
{
for(int i=0;i<=n;i++)
{
for(int j=0;j<=n;j++)
{
d[i][j]=min(d[i][j],d[i][k]+d[k][j]);
}
}
}
}
int main()
{
int n,m,k,l;
int tt,Case=0;
scanf("%d",&tt);
while(tt--)
{
scanf("%d%d%d%d",&n,&m,&k,&l);
for(int i=1;i<=n;i++)
scanf("%d",&a[i]);
for(int i=1;i<=n;i++)
scanf("%d",&b[i]);
memset(d,0x3f,sizeof(d));
memset(dp,0x3f,sizeof(dp));
for(int i=1;i<=m;i++)
{
int x,y,c;
scanf("%d%d%d",&x,&y,&c);
if(d[x][y]>c)
d[x][y]=d[y][x]=c;
}
floyd(n);///处理最短路。
dp[1][0]=0;
for(int i=0;i<(1<<(n+1));i++)///二进制枚举所有状态。
{
for(int j=0;j<=n;j++)///i状态中是否到过(1<<j)点
{
if(i&(1<<j))
{
for(int t=0;t<=n;t++)
{
if((1&(1<<t))==0) ///i状态没到过的点要加上。
dp[i|(1<<t)][t]=min(dp[i|(1<<t)][t],dp[i][j]+d[j][t]);
}
}
}
}
int ans=0;
for(int i=0;i<(1<<(n+1));i++)
{
int flag=0;
for(int j=0;j<=n;j++)
{
if(i&(1<<j) && dp[i][j]+d[j][0]<=l)///到过该点,并从该点返回起点距离是否超过l。
flag=1;
}
if(!flag)
continue;
int temp=0;
priority_queue<P>q;///优先队列取值,将a[i],b[i]用pair联系放到队列中。
for(int t=0;t<=n;t++)
{
if(i&(1<<t))///经过的点都放到队列中。
q.push(P(a[t],b[t]));
}
for(int t=0;t<k && !q.empty();t++)///最多取k次。
{
P pp=q.top();
q.pop();
temp=temp+pp.first;///加上权值a[i]。
pp.first-=pp.second;///减去b[i]。
q.push(pp);///再放回队列中。
}
ans=max(temp,ans);
}
printf("Case %d: %d\n",++Case,ans);
}
return 0;
}
Case 1: 7 Case 2: 16
Source
题意:有n+1个点,m条边,起点为0,除了0外其它点都有一个权值,一个人从0出发到达每一个点,再回到0。到达i点可以取i的权值a[i],取后权值将减少b[i]。最多可以取k次权值,并且总路程不能超过l。问最多能趣取到多少。
分析:首先是一个典型的TSP(商人旅行问题),拿状压dp跑一下,在此之前要对输入处理一下,拿floyd处理一下。最后再对l,k进行判断就行了。