zoukankan      html  css  js  c++  java
  • BZOJ1226或洛谷2157 [SDOI2009]学校食堂

    BZOJ原题链接

    洛谷原题链接

    注意到(B[i])很小,考虑状压(DP)
    (f[i][j][k])表示前(i - 1)个人已经拿到菜,第(i)个人及其后面(7)个人是否拿到菜的状态为(j),上一个拿到菜的人的编号为(i + k,-8leqslant k leqslant 7)时所用的最短时间。
    然后讨论状态的转移。

    • (j & 1)为真
      说明第(i)个人已经拿到菜,可以直接转移至(i + 1),即$$f[i + 1][j >> 1][k - 1] = min{ f[i + 1][j >> 1][k - 1], f[i][j][k] }$$
    • (j & 1)为假
      此时不能转移至(i + 1),因为第(i)个人还没拿到菜,不满足定义。
      于是我们可以枚举(q = 0 o 7),选出(i)后的第(q)个人去拿饭:$$f[i][j | (1 << h)][h] = min{ f[i][j | (1 << h)][h], f[i][j][k] + time(i + k, i + h) }$$
      (time(x,y))表示上一个拿菜的人的编号为(x),这次为(y),则需要做菜的时间。
      而在转移这种状态时,需要考虑每个人的容忍度,在循环(q)的过程中,维护一个最小的容忍度,若枚举到的人已经不被之前未拿菜的某人所容忍,那么就不需要考虑这个人与其之后的人了。

    最后答案为:(min limits ^ {-8leqslant k leqslant 0} { f[n + 1][0][k] })
    因为(k)可以为负,所以在储存是要整体右移。
    另外,题目中给出计算时间的公式((a | b) - (a & b)),实际上等于(a land b)

    #include<cstdio>
    #include<cstring>
    using namespace std;
    const int N = 1010;
    const int M = (1 << 8) + 10;
    int f[N][M][20], T[N], B[N];
    inline int re()
    {
    	int x = 0;
    	char c = getchar();
    	bool p = 0;
    	for (; c < '0' || c > '9'; c = getchar())
    		p |= c == '-';
    	for (; c >= '0' && c <= '9'; c = getchar())
    		x = x * 10 + c - '0';
    	return p ? -x : x;
    }
    inline void ckminn(int &x, int y)
    {
    	if (x > y)
    		x = y;
    }
    int main()
    {
    	int i, j, k, n, m = M - 10, t, q, edr, mi;
    	t = re();
    	while (t--)
    	{
    		n = re();
    		for (i = 1; i <= n; i++)
    		{
    			T[i] = re();
    			B[i] = re();
    		}
    		memset(f, 60, sizeof(f));
    		f[1][0][7] = 0;
    		for (i = 1; i <= n; i++)
    			for (j = 0; j < m; j++)
    				for (k = -8 ; k <= 7; k++)
    					if (f[i][j][k + 8] < 1e8)
    					{
    						if (j & 1)
    							ckminn(f[i + 1][j >> 1][k + 7], f[i][j][k + 8]);
    						else
    						{
    							edr = 1e9;
    							for (q = 0; q <= 7; q++)
    								if (!(j & (1 << q)))
    								{
    									if (i + q > edr)
    										break;
    									ckminn(edr, i + q + B[i + q]);
    									ckminn(f[i][j | (1 << q)][q + 8], f[i][j][k + 8] + (i + k ? T[i + k] ^ T[i + q] : 0));
    								}
    						}
    					}
    		for (mi = 1e9, i = 0; i <= 8; i++)
    			ckminn(mi, f[n + 1][0][i]);
    		printf("%d
    ", mi);
    	}
    	return 0;
    }
    
  • 相关阅读:
    SCILAB简介[z]
    UG OPEN API编程基础 2约定及编程初步
    Office 2003与Office 2010不能共存的解决方案
    UG OPEN API 编程基础 3用户界面接口
    NewtonRaphson method
    UG OPEN API编程基础 13MenuScript应用
    UG OPEN API编程基础 14API、UIStyler及MenuScript联合开发
    UG OPEN API编程基础 4部件文件的相关操作
    UG OPEN API编程基础 1概述
    16 UG Open的MFC应用
  • 原文地址:https://www.cnblogs.com/Iowa-Battleship/p/9843951.html
Copyright © 2011-2022 走看看