这周训练赛暂停了,周五,也就是明天会有一个比赛,想参加试试。
这周老师把专题的时间延长了,其意味不言而喻,看我们铁定达不成要求了,要把每个题目都要仔细研究。这周看了G这道题,题意大概是有n个Boss,其中有n-1个小boss必须先全部打完才能打第n个大BOSS,打一个小boss要耗体能usei,打完后恢复一部分vali,一开始体能为100,在打的过程中也最多为100,问能打完全部的BOSS? 如果能就输出“clear!!!”, 否则输出“try again”。准备用DP[i]表示打完i状态剩余的最大体能。
for(int i=1;i<(1<<(n-1));i++)
{
HP[i]=-9999;
for(int j=0;(1<<j)<=i;j++)
if(i&(1<<j)&&HP[i-(1<<j)]>=use[j])
{
int m=HP[i-(1<<j)]-use[j]+val[j];
if(m>100)m=100;
if(m>HP[i])HP[i]=m;
}
}
对于D题,题目大致的意思是一个人要送n份货,给出一个矩阵,表示任意两个点间的直接路径的时间,求从起点0送完这n份货(到达指定的n个地点)再回到起点0的最短时间,由于n本身不大,可以状态压缩,首先用弗洛伊德处理一下任意两点的最短路,dp[i][j]表示在状态i的条件下到城市j的最短时间,如果i == (1 << (j - 1)),表示从只经过城市j,这时候dp[i][j] = dis[0][j],否则就是要经过别的城市到达j,这里枚举当前状态下经过的除了j的其他城市,注意一定是当前状态下,这里类似Floyd,最后dp[(1 << n) - 1][i]表示经过了所有店到达i我们只要枚举dp[(1 << n) - 1][i] + dis[i][0]的最小值即可。
for(int i = 0; i <= (1 << n) - 1; i++)
{
for(int j = 1; j <= n; j++)
{
if(i == (1 << (j - 1)))
dp[i][j] = dis[0][j];
else
{
dp[i][j] = INF;
for(int k = 1; k <= n; k++)
if((k != j) && (i & (1 << (k - 1)))) //这里是当前状态下
dp[i][j] = min(dp[i][j], dp[i ^ (1 << (j - 1))][k] + dis[k][j]);
}
}
}
int ans = dp[(1 << n) - 1][1] + dis[1][0];
for(int i = 2; i <= n; i++)
{
ans = min(ans, dp[(1 << n) - 1][i] + dis[i][0]);
}