HDU 5691 Sitting in Line 状压dp

dp[i][j][k]代表到第i个位置,第i个位置是j,k为已经选了i个数分别是那些(2进制状压)

然后:其实真正有用的状态很少,可以写记忆化搜索,我写的BFS加速

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cmath>
#include <string>
#include <stack>
#include <vector>
#include <map>
#include <queue>
#include <algorithm>
#include <utility>
using namespace std;
typedef long long LL;
const int N=15;
const int INF=-15*(1e8+5);
const LL mod=1e9+7;
int dp[17][17][65537];
bool inq[17][17][65537];
int a[20],p[20],n;
int vis[20];
struct Node{
   int pos,u,cur;
   // Node(int a,int b,int c){pos=a;u=b;cur=c;}
};
queue<Node>q;
int main()
{
    int T,cas=0;
    scanf("%d",&T);
    while(T--){
       printf("Case #%d:\n",++cas);
       memset(vis,0,sizeof(vis));
       scanf("%d",&n);
       for(int i=1;i<=n;++i){
        scanf("%d%d",&a[i],&p[i]);
        if(p[i]!=-1){
            ++p[i];
            vis[p[i]]=i;
        }
       }
       int l=(1<<n)-1;
       for(int i=0;i<=n;++i)
        for(int j=0;j<=n;++j)
         for(int k=0;k<=l;++k)
          dp[i][j][k]=INF;
        memset(inq,0,sizeof(inq));
        q.push(Node{0,0,0});dp[0][0][0]=0;
        while(!q.empty()){
           Node e=q.front();
           q.pop();
           int pos=e.pos+1;
           if(vis[pos]&&(e.cur&(1<<(vis[pos]-1)))==0){
              int aim=e.cur|(1<<(vis[pos]-1));
              if(dp[pos][vis[pos]][aim]==INF)q.push(Node{pos,vis[pos],aim});
              dp[pos][vis[pos]][aim]=max(dp[pos][vis[pos]][aim],dp[e.pos][e.u][e.cur]+a[e.u]*a[vis[pos]]);
              continue;
           }
           for(int i=1;i<=n;++i){
              if(p[i]!=-1)continue;
              if(e.cur&(1<<(i-1)))continue;
              int aim=e.cur|(1<<(i-1));
              if(dp[pos][i][aim]==INF)q.push(Node{pos,i,aim});
              dp[pos][i][aim]=max(dp[pos][i][aim],dp[e.pos][e.u][e.cur]+a[e.u]*a[i]);
           }
        }
        int ans=INF;
        for(int i=1;i<=n;++i)
         ans=max(ans,dp[n][i][l]);
        printf("%d\n",ans);
    }
    return 0;
}

时间: 2024-10-05 12:59:01

HDU 5691 Sitting in Line 状压dp的相关文章

HDU 4114 Disney&#39;s FastPass (状压DP)

题意:给定 n 个区域,然后给定两个区域经过的时间,然后你有 k 个景点,然后给定个每个景点的区域和有票没票的等待时间,从哪些区域能够得到票,问你从景点1开始,最后到景点1,而且要经过看完这k个景点. 析:一个状压DP,dp[s1][s2][i] 表示已经访问了 s1 中的景点,拥有 s2 的票,当前在 i 区域,然后两种转移一种是去下一个景点,另一种是去下一个区域拿票.当时输入,写错了,卡了好长时间.... 代码如下: #pragma comment(linker, "/STACK:10240

POJ 2411 &amp;&amp; HDU 1400 Mondriaan&#39;s Dream (状压dp 经典题)

Mondriaan's Dream Time Limit: 3000MS   Memory Limit: 65536K Total Submissions: 12341   Accepted: 7204 Description Squares and rectangles fascinated the famous Dutch painter Piet Mondriaan. One night, after producing the drawings in his 'toilet series

HDU 4906 Our happy ending (状压DP)

HDU 4906 Our happy ending 题目链接 题意:给定n个数字,每个数字可以是0-l,要选其中一些数字,然后使得和为k,问方案 思路:状压dp,滚动数组,状态表示第i个数字,能组成的数字状态为s的状态,然后每次一个数字,循环枚举它要选取1 - min(l,k)的多少,然后进行状态转移 代码: #include <cstdio> #include <cstring> typedef long long ll; const int N = (1<<20)

HDU 4856 Tunnels(BFS+状压DP)

HDU 4856 Tunnels 题目链接 题意:给定一些管道,然后管道之间走是不用时间的,陆地上有障碍,陆地上走一步花费时间1,求遍历所有管道需要的最短时间,每个管道只能走一次 思路:先BFS预处理出两两管道的距离,然后状态压缩DP求解,dp[s][i]表示状态s,停在管道i时候的最小花费 代码: #include <cstdio> #include <cstring> #include <queue> #include <algorithm> using

hdu 5691 Sitting in Line

传送门 Sitting in Line Time Limit: 10000/5000 MS (Java/Others)    Memory Limit: 262144/262144 K (Java/Others)Total Submission(s): 293    Accepted Submission(s): 143 Problem Description 度度熊是他同时代中最伟大的数学家,一切数字都要听命于他.现在,又到了度度熊和他的数字仆人们玩排排坐游戏的时候了.游戏的规则十分简单,参与

HDU 5434 Peace small elephant 状压dp+矩阵快速幂

题目链接: http://acm.hdu.edu.cn/showproblem.php?pid=5434 Peace small elephant Accepts: 38 Submissions: 108 Time Limit: 10000/5000 MS (Java/Others) Memory Limit: 65536/65536 K (Java/Others) 问题描述 小明很喜欢国际象棋,尤其喜欢国际象棋里面的大象(只要无阻挡能够斜着走任意格),但是他觉得国际象棋里的大象太凶残了,于是他

HDU 1074 Doing Homework (状压dp)

题意:给你N(<=15)个作业,每个作业有最晚提交时间与需要做的时间,每次只能做一个作业,每个作业超出最晚提交时间一天扣一分 求出扣的最小分数,并输出做作业的顺序.如果有多个最小分数一样的话,则按照作业字典序输出(注意:输入也是按照字典序输入的) 题解:首先想到的是暴力dfs,但是会超时.接着我们看到n最大只有15,因此可以使用状压dp,但是状态不能用位置表示 但我们可以这样:0表示此作业没有做过,1表示已经用过了,接着遍历0->(1<<n)-1贪心(例如:3(011)可以找2(0

HDU 4568 Hunter 最短路+状压DP

题意:给一个n*m的格子,格子中有一些数,如果是正整数则为到此格子的花费,如果为-1表示此格子不可到,现在给k个宝藏的地点(k<=13),求一个人从边界外一点进入整个棋盘,然后拿走所有能拿走的宝藏的最小花费,如果一次不能拿走所有能拿到的或者根本拿不到任何宝藏,输出0. 解法:看到k的范围应该想到状态压缩,将每个格子都看成一个点,再新建两个点,一个表示边界外的起点,用0表示,一个表示边界外的终点,用n*m+1表示,然后相互建边,建有向边,边权为终点格子的花费值,(其实都不用建边,直接跑最短路也行)

HDU 5691 ——Sitting in Line——————【状压动规】

Sitting in Line Time Limit: 10000/5000 MS (Java/Others)    Memory Limit: 262144/262144 K (Java/Others)Total Submission(s): 597    Accepted Submission(s): 274 Problem Description 度度熊是他同时代中最伟大的数学家,一切数字都要听命于他.现在,又到了度度熊和他的数字仆人们玩排排坐游戏的时候了.游戏的规则十分简单,参与游戏的N