UVA - 1412 状压dp九进制表示状态

此题难点在于用九进制表示状态,并且转移

这里九进制用vector表示,再用map作为此状态特有的标记

此处用刷表法,每一种状态转移都经历一遍,最终状态就是正确答案,注意界限

#include<iostream>
#include<cstdio>
#include<cstring>
#include<string>
#include<map>
#include<stack>
#include<queue>
#include<algorithm>
#include<set>
#include<vector>
#include<cmath>
#define ll long long
#define maxn 200
#define MST(vis,x) memset(vis,x,sizeof(vis))
#define INF 0x3f3f3f3f
#define eps 1e-9
using namespace std;
vector<vector<int>> states;
map<vector<int>,int>ID;
char name[maxn][maxn];
int s[maxn],k[maxn];
double price[maxn][maxn];
double c;
int m,n,kk;
int buy_next[15005][maxn];
int sell_next[15005][maxn];
void dfs(int stock,vector<int>&lots,int totlot)
{
    if(stock==n)
    {
        ID[lots]=states.size();
        states.push_back(lots);
    }
    else for(int i=0;i<=k[stock]&&totlot+i<=kk;i++)
    {
        lots[stock]=i;
        dfs(stock+1,lots,totlot+i);
    }
}
void init()
{
    vector<int>lots(n);
    states.clear();
    ID.clear();
    dfs(0,lots,0);
    for(int s=0;s<states.size();s++)
    {
        int totlot=0;
        for(int i=0;i<n;i++)totlot+=states[s][i];
        for(int i=0;i<n;i++)
        {
            buy_next[s][i]=sell_next[s][i]=-1;
            if(states[s][i]<k[i]&&totlot<kk)
            {
                vector<int> newstates=states[s];
                newstates[i]++;
                buy_next[s][i]=ID[newstates];
            }
            if(states[s][i]>0)
            {
                vector<int>newstates=states[s];
                newstates[i]--;
                sell_next[s][i]=ID[newstates];
            }
        }
    }
}
double d[maxn][15005];
int opt[maxn][15005];
int prevv[maxn][15005];
void update(int day,int s,int s2,double v,int o)
{
    if(v>d[day+1][s2])
    {
        d[day+1][s2]=v;
        opt[day+1][s2]=o;
        prevv[day+1][s2]=s;
    }
}
double dp()
{
    for(int day=0;day<=m;day++)
        for(int s=0;s<states.size();s++)
        d[day][s]=-INF;
    d[0][0]=c;
    for(int day=0;day<=m;day++)
        for(int s=0;s<states.size();s++)
    {
        double v=d[day][s];
        if(v<-1)continue;
        update(day,s,s,v,0);
        for(int i=0;i<n;i++)
        {
            if(buy_next[s][i]>=0&&v>=price[i][day]-1e-3)
                update(day,s,buy_next[s][i],v-price[i][day],i+1);
            if(sell_next[s][i]>=0)
                update(day,s,sell_next[s][i],v+price[i][day],-i-1);
        }
    }
    return d[m][0];
}
void print_ans(int day,int s)
{
    if(day==0)return ;
    print_ans(day-1,prevv[day][s]);
    if(opt[day][s]==0)printf("HOLD\n");
    else if(opt[day][s]>0)printf("BUY %s\n",name[opt[day][s]-1]);
    else printf("SELL %s\n",name[-opt[day][s]-1]);
}
int main()
{
    int t=0;
    while(scanf("%lf%d%d%d",&c,&m,&n,&kk)!=EOF)
    {
        if(t++>0)printf("\n");
        for(int a=0;a<n;a++)
        {
            scanf("%s%d%d",name[a],&s[a],&k[a]);
            for(int i=0;i<m;i++)
            {
                scanf("%lf",&price[a][i]);
                price[a][i]*=s[a];
            }
        }
        init();
        double ans=dp();
        printf("%.2f\n",ans);
        print_ans(m,0);
    }
    return 0;
}
时间: 2024-10-28 22:48:26

UVA - 1412 状压dp九进制表示状态的相关文章

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

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

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的计算用到位运算,还

hdu 1185 状压dp 好题 (当前状态与上两行有关系)

/* 状压dp 刚开始&写成&&看了好长时间T0T. 状态转移方程 dp[i][k][j]=Max(dp[i][k][j],dp[i-1][l][k]+num[i][j]);(第i行的第j个状态有上一行的第k个状态得到) num[i][j]有两个功能,第一:判断第i行第j个状态是否合法 第二:判断第i行第j个状态的数目 */ #include<stdio.h> #include<string.h> #define N 110 int dp[N][N][N];

Sharing Chocolate - UVa 1099 状压dp

Chocolate in its many forms is enjoyed by millions of people around the world every day. It is a truly universal candy available in virtually every country around the world. You find that the only thing better than eating chocolate is to share it wit

HDU3001(状压DP,三进制)

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=3001 Travelling Time Limit: 6000/3000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total Submission(s): 11880    Accepted Submission(s): 3736 Problem Description After coding so many days

UVa 1252 (状压DP + 记忆化搜索) Twenty Questions

题意: 有n个长为m的各不相同的二进制数(允许存在前导0),别人已经事先想好n个数中的一个数W,你要猜出这个数. 每次只可以询问该数的第K为是否为1. 问采用最优询问策略,则最少需要询问多少次能保证猜到. 比如有1100 和 0110两个数,只需要询问第一或第三位数是否为1,即可猜中,因此答案为1. 分析: d(s, a)表示已经询问了的集合s,在已经询问了的集合中W中为1的集合为a,还需要询问多少次. 如果下一次询问第k位,则询问次数为: 然后取所有k里的最小值即可. 预处理: 对于每个s和a

UVA - 11825 状压DP

该题目是EMAXX推荐的练习题,刘汝佳的书也有解说 如果S0属于全集,那S0就可以作为一个分组,那么S分组数可以是best{当前S中S0的补集+1} 对于集合类的题目我觉得有点抽象,希望多做多理解把 #include<iostream> #include<algorithm> #include<cstdio> #include<cstring> #include<cstdlib> #include<cmath> #include<

UVa 12235 状压DP Help Bubu

题解戳这 一开始没看懂题解,后来想明白以后,d(i, j, s, x)是考虑第i本书的时候,前面已经拿走了j本书,剩下的书的种类的二进制状态为s,剩下的最后一本书的编号为x,所能得到的最小混乱度. 这里状态定义的时候,先不考虑把拿出来的书放回去. 最后统计答案的时候,把那些拿出来的书再加上. all是所有n本书的状态,s是剩下书的种类的状态. 如果拿出来的书中有和前面高度相同的,直接插到相邻的位置就行了,不会增加混乱度. 如果拿出来的书中没有和前面高度相同的,不管放在那里混乱度都会加1,这样所增

POJ 2411 Mondriaan&#39;s Dream(状压DP)

http://poj.org/problem?id=2411 求一个n*m矩阵用1*2方块去填满的情况有几种 思路:状压dp,先预处理那些状态之间能互相到达,情况就几种,上一个两个1,下一个状态也两个1,上一个为0,下一个必须为1,还有一种是上一个为1,下一个为0的情况 然后就一层层往后递推即可 代码: #include <stdio.h> #include <string.h> #include <algorithm> using namespace std; int