P2157 [SDOI2009]学校食堂 状压DP

题意:  

  排队买饭,时间为前一个人和后一个人的异或和,每个人允许其后面B【i】 个人先买到饭,问最少的总用时。

思路:

  用dp【i】【j】【k】 表示1~i-1已经买好饭了,第i个人后面买饭情况为j,最后一个打饭的是i+k。

#include <algorithm>
#include  <iterator>
#include  <iostream>
#include   <cstring>
#include   <cstdlib>
#include   <iomanip>
#include    <bitset>
#include    <cctype>
#include    <cstdio>
#include    <string>
#include    <vector>
#include     <stack>
#include     <cmath>
#include     <queue>
#include      <list>
#include       <map>
#include       <set>
#include   <cassert>

using namespace std;
#define lson (l , mid , rt << 1)
#define rson (mid + 1 , r , rt << 1 | 1)
#define debug(x) cerr << #x << " = " << x << "\n";
#define pb push_back
#define pq priority_queue

typedef long long ll;
typedef unsigned long long ull;
//typedef __int128 bll;
typedef pair<ll ,ll > pll;
typedef pair<int ,int > pii;
typedef pair<int,pii> p3;

//priority_queue<int> q;//这是一个大根堆q
//priority_queue<int,vector<int>,greater<int> >q;//这是一个小根堆q
#define fi first
#define se second
//#define endl ‘\n‘

#define OKC ios::sync_with_stdio(false);cin.tie(0)
#define FT(A,B,C) for(int A=B;A <= C;++A)  //用来压行
#define REP(i , j , k)  for(int i = j ; i <  k ; ++i)
#define max3(a,b,c) max(max(a,b), c);
#define min3(a,b,c) min(min(a,b), c);
//priority_queue<int ,vector<int>, greater<int> >que;

const ll mos = 0x7FFFFFFF;  //2147483647
const ll nmos = 0x80000000;  //-2147483648
const int inf = 0x3f3f3f3f;
const ll inff = 0x3f3f3f3f3f3f3f3f; //18
const int mod = 1000000007;
const double esp = 1e-8;
const double PI=acos(-1.0);
const double PHI=0.61803399;    //黄金分割点
const double tPHI=0.38196601;

template<typename T>
inline T read(T&x){
    x=0;int f=0;char ch=getchar();
    while (ch<‘0‘||ch>‘9‘) f|=(ch==‘-‘),ch=getchar();
    while (ch>=‘0‘&&ch<=‘9‘) x=x*10+ch-‘0‘,ch=getchar();
    return x=f?-x:x;
}
/*-----------------------showtime----------------------*/
            const int maxn = 1009;

            int dp[maxn][1<<8][20];
            int A[maxn],B[maxn];
            int cal(int q,int h){
                if(q == 0) return 0;
                return A[q] ^ A[h];
            }

            void solve(){
                int n;  scanf("%d", &n);
                for(int i=1; i<=n; i++) scanf("%d%d", &A[i], &B[i]);
                memset(dp, inf, sizeof(dp));
                dp[1][0][7] = 0;

                for(int i=1; i<=n; i++)  for(int j=0; j<(1<<8); j++){
                    for(int k=-8; k<=7; k++) if(dp[i][j][k+8] < inf){
                        if(j & 1) dp[i+1][j>>1][k+7] = min(dp[i+1][j>>1][k+7], dp[i][j][k+8]);
                        else {
                            int mx = inf;
                            for(int h = 0; h<=7; h++) if(! (j & (1<<h))){
                                if(i + h > mx) break;
                                mx = min(mx, i + h + B[i+h]);
                                int tmp = dp[i][j][k + 8] + cal(i + k, i + h);
                                dp[i][j | (1 << h)][h + 8] = min(dp[i][j | (1 << h)][h + 8], tmp);
                            }
                        }
                    }
                }
                int ans = inf;
                for(int i=0; i<=8; i++) ans = min(ans, dp[n+1][0][i]);
                cout<<ans<<endl;
            }
int main(){
            int T;  scanf("%d", &T);
            while(T--){
                solve();
            }
            return 0;
}

原文地址:https://www.cnblogs.com/ckxkexing/p/10348316.html

时间: 2024-11-07 19:36:47

P2157 [SDOI2009]学校食堂 状压DP的相关文章

【题解】Luogu P2157 [SDOI2009]学校食堂

原题传送门:P2157 [SDOI2009]学校食堂 一看题目就知道是状压dp 设f[i][j][k]表示第1到i-1个人都吃完了饭,第i个人以及后面的7个人是否打饭的状态为j,当前最后打饭的人的编号为i+k(-8<=k<=7) 开始设计状态转移方程 当j&1为真,表示i之后的7个人中,不再会有人插队到i之前 可得:f[i + 1][j >> 1][k - 1]=Min(f[i + 1][j >> 1][k -1],f[i][j][k]) 当j&1为假,

P2157 [SDOI2009]学校食堂

题目描述 小F 的学校在城市的一个偏僻角落,所有学生都只好在学校吃饭.学校有一个食堂,虽然简陋,但食堂大厨总能做出让同学们满意的菜肴.当然,不同的人口味也不一定相同,但每个人的口味都可以用一个非负整数表示. 由于人手不够,食堂每次只能为一个人做菜.做每道菜所需的时间是和前一道菜有关的,若前一道菜的对应的口味是a,这一道为b,则做这道菜所需的时间为(a or b)-(a and b),而做第一道菜是不需要计算时间的.其中,or 和and 表示整数逐位或运算及逐位与运算,C语言中对应的运算符为“|”

P2157 [SDOI2009]学校食堂Dining

题目描述 小F 的学校在城市的一个偏僻角落,所有学生都只好在学校吃饭.学校有一个食堂,虽然简陋,但食堂大厨总能做出让同学们满意的菜肴.当然,不同的人口味也不一定相同,但每个人的口味都可以用一个非负整数表示. 由于人手不够,食堂每次只能为一个人做菜.做每道菜所需的时间是和前一道菜有关的,若前一道菜的对应的口味是a,这一道为b,则做这道菜所需的时间为(a or b)-(a and b),而做第一道菜是不需要计算时间的.其中,or 和and 表示整数逐位或运算及逐位与运算,C语言中对应的运算符为"|&

bzoj 1226 [SDOI2009]学校食堂Dining(状压DP)

Description 小F 的学校在城市的一个偏僻角落,所有学生都只好在学校吃饭.学校有一个食堂,虽然简陋,但食堂大厨总能做出让同学们满意的菜肴.当然,不同的人口味也不一定相同,但每个人的口味都可以用一个非负整数表示.由于人手不够,食堂每次只能为一个人做菜.做每道菜所需的时间是和前一道菜有关的,若前一道菜的对应的口味是a,这一道为b,则做这道菜所需的时间为(a or b)-(a and b),而做第一道菜是不需要计算时间的.其中,or 和and 表示整数逐位或运算及逐位与运算,C语言中对应的运

【BZOJ1226】[SDOI2009]学校食堂Dining 状压DP

[BZOJ1226][SDOI2009]学校食堂Dining Description 小F 的学校在城市的一个偏僻角落,所有学生都只好在学校吃饭.学校有一个食堂,虽然简陋,但食堂大厨总能做出让同学们满意的菜肴.当然,不同的人口味也不一定相同,但每个人的口味都可以用一个非负整数表示.由于人手不够,食堂每次只能为一个人做菜.做每道菜所需的时间是和前一道菜有关的,若前一道菜的对应的口味是a,这一道为b,则做这道菜所需的时间为(a or b)-(a and b),而做第一道菜是不需要计算时间的.其中,o

[bzoj1879][Sdoi2009]Bill的挑战_动态规划_状压dp

Bill的挑战 bzoj-1879 Sdoi-2009 题目大意: 注释:$1\le t \le 5$,$1\le m \le 15$,$1\le length \le 50$. 想法: 又是一个看数据范围想做法的题,我们想到状压dp. 看了题解... ...网上给的状态是f[len][s]表示长度为len满足状态s的字符串个数. 光看状态... ...可能算重啊?! 其实... ... 状态:dp[len][s]表示长度为len,能且只能满足状态为s的字符串个数. 转移:我们先预处理出g[i]

bzoj 1879 [Sdoi2009]Bill的挑战(状压DP)

Description  Input 本题包含多组数据. 第一行:一个整数T,表示数据的个数. 对于每组数据: 第一行:两个整数,N和K(含义如题目表述). 接下来N行:每行一个字符串. Output 1 2 1 a? ?b Sample Input 50 Sample Output 对于30%的数据,T ≤ 5,M ≤ 5,字符串长度≤ 20: 对于70%的数据,T ≤ 5,M ≤ 13,字符串长度≤ 30: 对于100%的数据,T ≤ 5,M ≤ 15,字符串长度≤ 50. [思路] 状压D

bzoj 1879: [Sdoi2009]Bill的挑战【状压dp】

石乐志写容斥--其实状压dp就行 设f[i][s]表示前i个字母,匹配状态为s,预处理g[i][j]为第i个字母是j的1~n的集合,转移的时候枚举26个字母转移,最后答案加上正好有k个的方案即可 #include<iostream> #include<cstdio> #include<cstring> using namespace std; const int mod=1000003; int T,n,m,len,t,f[55][50005],g[55][27],an

【vijos】1286 座位安排(状压dp)

https://vijos.org/p/1286 这题好神不会捉... 首先我们知道所有情况有C(n*m, k)种,这个好搞.但是两两不相邻这个有点难搞.. 原来是状压dp..sigh. 设状态f[i][j][k]表示第i行放置的摆放状态是j放了k个人的方案,那么有 f[i][j][k]=sum{f[i-1][x][k-num[x]]},当j的人两两不冲突,且j和x的人两两不冲突,num[x]是x状态的人的数量 最后不冲突的数目是sum{f[n][j][k]},k是题目所给的,j是所有的状态 显