uva 1379 - Pitcher Rotation(dp)

题目链接:uva 1379 - Pitcher Rotation

题目大意:给出n,表示由n个人组成的战队,接着是m,表示有m个敌人,g表示要比赛的天数,给出g后,比赛的天数起始是g+10,然后是一个m*n的矩阵,g[i][j]表示第j个敌人被i打败后,战队所得到的分数。然后g+10个数,表示每天需要挑战的敌人是谁,0代表说休息;每个人出战的次数没有限制,但是比过一场后要休息4天,问说战队的最高得分。

解题思路:注意题目中的一点,说每个人比完一场赛后要休息4天,那么也就是说对于每个敌人来说,被派去和他打的人就只可能是得分比较高的5个。所以只用开dp[i][a][b][c][d]表示第i天时,第i-1天为a,i-2为b,i-3为c,i-4为d(这里的a,b,c,d表示说那天所对应敌人的前5个较大得分的序号)然后转移到dp[i+1][x][a][b][c],x所对应的序号要和a,b,c,d对应的人的序号不同。

#include <cstdio>
#include <cstring>
#include <algorithm>

using namespace std;
const int N = 105;
const int M = 10;

struct state {
	int val, u;
}g[N][N];

int n, m, d, t[N*3];
int dp[2][M][M][M][M];

inline bool cmp (const state& a, const state& b) {
	return a.val > b.val;
}

inline int cat (int j, int i) {
	if (j == 0 || i == 0)
		return 0;
	return g[i][j].u;
}

void init () {
	scanf("%d%d%d", &n, &m, &d);
	for (int i = 1; i <= m; i++) {
		for (int j = 1; j <= n; j++) {
			scanf("%d", &g[i][j].val);
			g[i][j].u = j;
		}
		sort(g[i]+1, g[i] + n + 1, cmp);
	}

	d += 10;

	for (int i = 1; i <= d; i++)
		scanf("%d", &t[i]);
}

double solve () {
	memset(dp[0], 0, sizeof(dp[0]));

	for (int i = 1; i <= d; i++) {
		int now = i%2;
		int pre = 1-now;

		memset(dp[now], 0, sizeof(dp[now]));

		if (t[i]) {

			for (int j = 1; j <= 5; j++) {
				for (int x = 0; x <= 5; x++) {
					if (i > 1 && cat(j, t[i]) == cat(x, t[i-1])) continue;

					for (int y = 0; y <= 5; y++) {
						if (i > 2 && cat(j, t[i]) == cat(y, t[i-2])) continue;

						for (int z = 0; z <= 5; z++) {
							if (i > 3 && cat(j, t[i]) == cat(z, t[i-3])) continue;

							for (int a = 0; a <= 5; a++) {
								if (i > 4 && cat(j, t[i]) == cat(a, t[i-4])) continue;
								dp[now][j][x][y][z] = max(dp[now][j][x][y][z], dp[pre][x][y][z][a] + g[t[i]][j].val);
							}
						}
					}
				}
			}
		} else {

			for (int x = 0; x <= 5; x++) {
				for (int y = 0; y <= 5; y++) {
					for (int z = 0; z <= 5; z++) {
						for (int a = 0; a <= 5; a++) {
							dp[now][0][x][y][z] = max(dp[now][0][x][y][z], dp[pre][x][y][z][a]);
						}
					}
				}
			}
		}
	}

	int ans = 0;
	int u = d%1;

	for (int x = 0; x <= 5; x++)
		for (int y = 0; y <= 5; y++)
			for (int z = 0; z <= 5; z++)
				for (int a = 0; a <= 5; a++)
					ans = max(ans, dp[u][x][y][z][a]);
	return ans / 100.0;
}

int main () {
	int cas;
	scanf("%d", &cas);
	while (cas--) {
		init ();
		printf("%.2lf\n", solve());
	}
	return 0;
}

uva 1379 - Pitcher Rotation(dp),布布扣,bubuko.com

时间: 2024-10-05 18:59:20

uva 1379 - Pitcher Rotation(dp)的相关文章

UVA 1379 - Pitcher Rotation(DP + 贪心)

题目链接:1379 - Pitcher Rotation 题意:n个人,m个敌人,去比赛,有得分,n个人可以重复比,但是每次比完要休息4天,问最大得分 思路:dp[i][j][k][l][x] 表示第场比赛,前一天为j,两天为k,三天为l,四天为x,的最大得分,然后由于只有每个人5天就能用一次,所以对于每个人来说,只有得分前5的会被使用上,所以后4维状态只需要5^4,进行状态转移,不用比赛的情况分开考虑,还有这题内存有限,要用滚动数组优化不然会RE 代码: #include <stdio.h>

[UVA 12589]Learning Vector[DP]

题目链接:[UVA 12589]Learning Vector[DP] 题意分析:给出n个矢量,从中选择k个,以坐标原点为起点,收尾相连,问:这样的k个周围相连矢量与x轴围成图形的最大面积的两倍是多少? 解题思路:考虑状态:dp[id][pick][h]代表到第id个矢量为止,选择pick个矢量离最大面积还差多少,h为当前图形最右端高度.具体转移看代码. 这里着重说一下为什么要对这些矢量按斜率进行排序: 首先,整个求解过程其实就是在暴力枚举这些向量的组合,只不过采用了记忆化搜索优化. 其次,对于

Uva 12018 Juice Extractor dp

题目链接:点击打开链接 题意: 切水果游戏 给出n个水果 水果出现在屏幕上的时间的区间 1.每次切会把屏幕上所有水果切完 2.当同时切3个或以上时计分,分数为切的水果个数 3.不能遗漏水果 问最高得分 dp[i] 表示 最后一次切第i个的得分. #include<stdio.h> #include<algorithm> #include<string.h> #include<iostream> using namespace std; #define N 1

uva 11578 - Situp Benches(dp+输出路径)

题目连接:uva 11578 - Situp Benches 题目大意:健身房有两个仪器,初始角度为10度,每次有人使用需要交15元,每调10度需要花费10元,现在有n个人,给出每个人使用仪器的顺序和角度,保证不会同时有大于2个人序号一样,求最小花费,并且输出每个人分别使用哪一个仪器,并且所有人使用结束后,要将仪器调回10度. 解题思路:dp[i][x][y]表示第i个人,一个仪器为x,另一个仪器为y的情况,path[i][x][y]记录的是它的前一个状态,[0]为前一个仪器的夹角,[1]为另一

uva 10269 最短路+dp

题意:有a个村庄.b个城镇, 编号分别为:1-a , a+1--a+b . 有双神奇的鞋,可以瞬时移动,可以使用k次,每次可以移动L , 但穿这双鞋的时候,不能经过城镇 , 问:从a+b 到 1 最短距离是多少? 刚开始看这个题时 , 一点思路都没有 , dp类型的题目做得太少了. 解法:进行状态压缩, 用点+使用鞋子的次数 , 来表示一个状态 , d[i][k] , 表示到 点 i 使用 k 次鞋子的最短距离是多少. 但要先进行初始化 , 求任意点之间不经过城镇的最短距离 , 用floyd算法

uva 10671 - Grid Speed(dp)

题目链接:uva 10671 - Grid Speed 题目大意:给出N,表示在一个N*N的网格中,每段路长L,现在给出h,v的限制速度,以及起始位置sx,sy,终止位置ex,ey,时间范围st,et,车只走最短路,问说在范围内最快到达和耗油量最小的情况下时间和耗油量. 解题思路:dp[x][y][t]表示在x,y这一点,时间为t的耗油量最小为dp[x][y][t],vis[x][y][t]表示该情况是否可达.dx,dy表示由起点向终点移动的方向.因为时间为L?60v, 因为v是5的倍数,并且小

UVA 1559 - Nim(博弈dp)

UVA 1559 - Nim 题目链接 题意:一开始有s个石子,2n个人轮流取石子,每个人有个最大能取数目,2n个人奇数一队,偶数一队,取到最后一个石子的队输,问谁赢 思路:记忆化搜索,每个人取的时候对应的后继状态如果有一个必败态,则该状态为必胜态,如果都是必胜态,则该状态为必败态 代码: #include <stdio.h> #include <string.h> int n, s, m[25], dp[25][10005]; int dfs(int now, int state

UVa 10817 (状压DP + 记忆化搜索) Headmaster&#39;s Headache

题意: 一共有s(s ≤ 8)门课程,有m个在职教师,n个求职教师. 每个教师有各自的工资要求,还有他能教授的课程,可以是一门或者多门. 要求在职教师不能辞退,问如何录用应聘者,才能使得每门课只少有两个老师教而且使得总工资最少. 分析: 因为s很小,所以可以用状态压缩. dp(i, s1, s2)表示考虑了前i个人,有一个人教的课程的集合为s1,至少有两个人教的集合为s2. 在递归的过程中,还有个参数s0,表示还没有人教的科目的集合. 其中m0, m1, s0, s1, s2的计算用到位运算,还

UVa 11825 (状压DP) Hackers&#39; Crackdown

这是我做状压DP的第一道题,状压里面都是用位运算来完成的,只要耐下心来弄明白每次位运算的含义,还是容易理解的. 题意: 有编号为0~n-1的n台服务器,每台都运行着n中服务,每台服务器还和若干台其他服务器相连.对于每台服务器,你可以选择停止该台以及与这台服务器相连的服务器的一项服务.如果一台服务器的所有服务都被停止,则这台服务器瘫痪.问最多能使多少台服务器瘫痪 转化为数学模型(题目是如何抽象成这种数学模型的也要好好想想): 把n个集合尽可能多的分成若干组,使得每组所有集合的并集为全集.这里集合P