状态压缩DP[自信心-hihocoder编程练习赛19]

1540 : 自信心

时间限制:10000ms
单点时限:1000ms
内存限制:256MB

描述

有 n 个学生按照序号从左到右依次排成一排进行考试。这 n 个学生的学习能力两两不同。对于第 i 个学生,如果有 j 个同学比他学习能力差且和他的座位之间最多隔一个位置,那么 i 同学考试时的自信心为 Aij。

但不幸的是,记录学生学习能力的表格丢失了。作为一个悲观的人A老师想请你帮助他计算出最坏情况下学生自信心总和为多少,即最小可能为多少。

输入

第一行一个数 T,表示数据组数
对于每一组数据:
第一行一个数 n
接下来 n 行,每行5个数分别表示 Ai0 ~ Ai4

对于30%的数据,1 ≤ n ≤ 10
对于50%的数据,1 ≤ n ≤ 100
对于100%的数据,1 ≤ T ≤ 10, 1 ≤ n ≤ 100000, 1 ≤ Aij ≤ 10000

输出

对于每组数据输出一个数,表示答案

样例输入

1
3
1 2 3 4 5
2 1 3 4 5
2 3 1 4 5

样例输出

3

分析

首先是生成全排列的方法,可以拿30分,就不说了。

这个题很明显是要DP的,我们可以设前i个学生的最小自信心总和为f[i],显然第i个人的取值取决于i前两人和后两人相对于他的关系,因此考虑设f[i][j]代表区间[i-2,i+2]五个人的相对排名为j的时候,前i个人的最小总和。其中,j是一个[1,5]的全排列,例如j=(4,1,5,3,2)时,代表第i-2,i-1,i,i+1,i+2人在这五个人之中的相对排名为4,1,5,3,2。
这么做的话,转移的时候就非常方便了,对于任意一个f[i][j],根据j就可以确定f[i-1][k]中k的后四人的相对排名,而k中第一人的相对排名可以枚举从1到5插入到后四人中。
例如j=(4,1,5,3,2)时,前四人的相对排名是(4,1,5,3)->(3,1,4,2)
即k中后四人的相对排名应该是(3,1,4,2),那么枚举第一人的排名,可以得到k可能的排列是:
(1,4,2,5,3),(2,4,1,5,3),(3,4,1,5,2),(4,3,1,5,2),(5,3,1,4,2)

同时,根据状态f[i][j],j的第三位,也就是i的排名,可以直接得到他的自信心的取值为:a[i][5-排名],所以状态转移方程为:

需要注意的是边界条件(问号处是一个2~5的排列):

这个很好理解,第0个人不会影响到后面的人的自信心,所以直接假设他的相对排名是第一就好了。同理,最后我们要求的状态便是:

这里需要注意的是关于状态j的存储,由于j是一个1~5的全排列,所以可以根据康托展开直接映射到区间[1,120]上。所以不需要开5维,这个映射可以事先预处理并保存下来。同样可以预处理的是j所有可以用于转移的状态k。容易发现,对于任何一个状态j,能转移到j的状态k都只有5个,没必要每次都去枚举状态,也可以事先预处理并保存。

最后分析一下复杂度,状态量总共是N*5!,转移的复杂度是5,总的复杂度就是N * 600,最坏情况下,由于还有T=10组数据,总的来看可以说是AC得非常惊险,最后运行时间好像是940ms= =。。。

PS:官方题解的状态表示比我的要优秀,复杂度也小很多,不过我没看太懂,就不说了ORZ_

AC代码:

#include<stdio.h>
#include<string.h>
#include<math.h>
#include<stdlib.h>
#include<time.h>
#include<algorithm>
#include<iostream>
#include<queue>
#include<map>
#include<string>
#include<stack>
#include<set>
#define mem(f) memset(f,0,sizeof(f))
#define P2 pair<LL,LL>
#define double char
typedef long long LL;
using namespace std;
const LL MOD = 1e9+7;
const int N = 200005;
const int MININT = 0x80000000;
const int MAXINT = 0x3FFFFFFF;
int n,z[N][5],f[N][121];
int facts[]={1,1,2,6,24,120,720};
vector<int> trans[121];
vector<int> lis[121];
void init()
{
    int i;
    cin >> n;
    for(i=1;i<=n;i++)
        scanf("%d%d%d%d%d",&z[i][0],&z[i][1],&z[i][2],&z[i][3],&z[i][4]);
}

vector<int> reverse_kangtuo(int n,int k)
{
    int i, j, t, vst[8]={0};
    vector<int> s;
    --k;
    for (i=0; i<n; i++)
    {
        t = k/facts[n-i-1];
        for (j=1; j<=n; j++)
            if (!vst[j])
            {
                if (t == 0) break;
                --t;
            }
        s.push_back(j);
        vst[j] = 1;
        k %= facts[n-i-1];
    }
    return s;
}

int kangtuo(int n,vector<int> a)
{
    int i,j,t,sum;
    sum=0;
    for( i=0; i<n ;++i)
    {
        t=0;
        for(j=i+1;j<n;++j)
            if( a[i]>a[j] )
                ++t;
        sum+=t*facts[n-i-1];
    }
    return sum+1;
}

void prep()
{
    int i,j,k;
    for(i=1;i<=120;i++)
    {
        vector <int> st1=reverse_kangtuo(5,i);
        lis[i]=st1;
        vector <int> st2(5);
        st2.assign(st1.begin()+1,st1.begin()+5);st2.push_back(0);
        for(j=0;j<4;j++)
            if(st2[j]>st1[0]) st2[j]--;
        vector <int> st3;
        for(k=1;k<=5;k++)
        {
            st3=st2;
            st3[4]=k;
            for(j=0;j<4;j++)
                if(st3[j]>=k) st3[j]++;
            trans[kangtuo(5,st3)].push_back(i);
        }
    }
}

void work()
{
    int i,j,k,ans=MAXINT;
    for(i=0;i<=n;++i)
        for(j=0;j<=120;++j)
            f[i][j]=MAXINT;
    for(j=1;j<=120;j++)
        if(lis[j][3]>3&&lis[j][4]>3)
            f[0][j]=0;
    for(i=1;i<=n;++i)
        for(j=1;j<=120;++j)
            for(k=0;k<5;++k)
            {
                f[i][j]=min(f[i][j],f[i-1][trans[j][k]]+z[i][5-lis[j][2]]);
                if(i==n&&lis[j][3]<3&&lis[j][4]<3)
                    ans=min(ans,f[i][j]);
            }
    cout << ans << endl;
}

int main()
{
    freopen("input.txt","r",stdin);
    //freopen("output.txt","w",stdout);
    prep();
    int t;
    scanf("%d\n",&t);
    while(t--)
    //while(cin >> n)
    {
        init();
        work();
    }
    return 0;
}

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,684评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 87,143评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,214评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,788评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,796评论 5 368
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,665评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,027评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,679评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 41,346评论 1 299
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,664评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,766评论 1 331
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,412评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,015评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,974评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,203评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,073评论 2 350
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,501评论 2 343

推荐阅读更多精彩内容

  • 背景 一年多以前我在知乎上答了有关LeetCode的问题, 分享了一些自己做题目的经验。 张土汪:刷leetcod...
    土汪阅读 12,723评论 0 33
  • 红泥小火炉,绿蚁新醅酒。 晚来天欲雪,能饮一杯无? 喜欢这样让人觉得温暖的词句,烟台今天也开始飘雪,和母上大人打电...
    Subyfu阅读 235评论 0 0
  • 才华会枯竭 容貌会衰老 钱会花光 经历也会从财富变成拖住脚步的负累 所以要是你爱一个人 要去爱他的那颗心和大脑 感...
    Abbyyyyyy666阅读 187评论 0 0
  • 主观感性和客观理性 我常常能看到很多女孩,包括从前的我也一样,对着电脑,对着手机,对着别人的故事唉声叹气然后和别人...
    北森随想阅读 311评论 0 0
  • 写于2015年11月10日 “生活就像一盒巧克力,你永远不知道下一个是什么味道。” 秋天的郑州多了点凉意,早晚的巨...
    敏敏的日记阅读 715评论 0 0