p1292监狱(动态规划)

描述 Description
小X的王国中有一个奇怪的监狱,这个监狱一共有P个牢房,这些牢房一字排开,第i个仅挨着第i+1个(最后一个除外),当然第i个也挨着第i-1个(第一个除外),现在牢房正好是满员的。
上级下发了一个释放名单,要求每天释放名单上的一个人。这可把看守们吓得不轻,因为看守们知道,现在牢房里的P个人,可以相互之间传话。第i个人可以把话传给第i+1个,当然也能传给第i-1个,并且犯人很乐意把消息传递下去。
如果某个人离开了,那么原来和这个人能说上话的人,都会很气愤,导致他们那天会一直大吼大叫,搞得看守很头疼。如果给这些要发火的人吃上肉,他们就会安静下来。
为了河蟹社会,现在看守们想知道,如何安排释放的顺序,才能是的他们消耗的肉钱最少。

输入格式 Input Format
第一行两个数P和Q,Q表示释放名单上的人数;
第二行Q个数,表示要释放哪些人。

输出格式 Output Format
仅一行,表示最少要给多少人次送肉吃。

样例输入 Sample Input
20 3
3 6 14

样例输出 Sample Output
35
样例解释: 先放14号犯人,给19个人肉吃,再放6号犯人,给12个人肉吃,最后放3号,给4个人肉吃,一共35个。

时间限制 Time Limitation
1s

注释 Hint
【数据规模】
1<=P<=1000; 1<=Q<=100.
Q<=P,且 50%的数据 1<=P<=100;1<=Q<=5;

来源 Source
codejam

        (还是得回来搞动规哇)

        这道题就是一个区间动态规划的题,因为一共要放出来m个罪犯,但是没放出来一个罪犯后,能和这个罪犯说到话的人都会很生气,所以必须要给他们吃肉。。。。。所以就用一个数组sun[i]来记录释放第i个罪犯前需要支付的肉之和,然后用f[i][j]表示释放i到j中的罪犯最少需要多少肉,所以就可以知接在i到j中枚举出k,所以

        f[i][j]=min(f[i][j],f[i][k]+f[k+1][j]+sum[j]-sum[i-1]+j-i-1);

//动规还是掌握的不好啊还得多写点题

代码如下:

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
using namespace std;
int a[1100];
int f[1100][1100];
int sum[1110];
int main()
{
    memset(a,0,sizeof(a));
    memset(f,10,sizeof(f));
    memset(sum,0,sizeof(sum));
    int n,m;
    cin>>n>>m;
    for(int i=1;i<=m;i++)
        cin>>a[i];
    sort(a+1,a+1+m);
    for(int i=1;i<=m;i++)
    {
        sum[i]=a[i]-a[i-1]-1;
        f[i][i]=0;
    }
    sum[m+1]=n-a[m];
    for(int i=1;i<=m+1;i++)
        sum[i]=sum[i]+sum[i-1];
    f[0][0]=0;
    f[m+1][m+1]=0;
    for(int i=m+1;i>=1;i--)
    {
        for(int j=i+1;j<=m+1;j++)
        {
            for(int k=i;k<j;k++)
            {
                f[i][j]=min(f[i][j],f[i][k]+f[k+1][j]+sum[j]-sum[i-1]+j-i-1);
            }
        }
    }
    cout<<f[1][m+1]<<endl;
    return 0;
}

ε(┬┬﹏┬┬)3

时间: 2024-10-09 08:05:34

p1292监狱(动态规划)的相关文章

编程题-贿赂囚犯(Bribe the prisoners)-动态规划|剪枝

转载请注明出处:http://blog.csdn.net/Lizo_Is_Me/article/details/43735509 问题描述: 一个监狱里有P个并排着的牢房,从左往右一次编号为1,2,-,P.最初所有牢房里面都住着一个囚犯.现在要释放一些囚犯.如果释放某个牢房里的囚犯,必须要贿赂两边所有的囚犯一个金币,直到监狱的两端或者空牢房为止.现在要释放a1,a2,...,aQ号囚犯,如何选择释放的顺序,使得使用的金币最少. 思路: 其中很重要的一点:释放了某个囚犯以后,就把连续的牢房分成了没

POJ1636 动态规划+并查集

POJ1636 问题重述: 两个监狱中各有m个囚犯,欲对这两个监狱中的囚犯进行等数量的交换.已知某些囚犯不能关押在同一个监狱,求解可以交换人数的最大值k (k < m/2). 分析: 假设监狱1中的囚犯a与监狱2中的囚犯b不能共存.那么假如对a进行交换,也必须对b进行交换.因此,根据互斥关系建立的连通集两边的成员必须同时进行交换. 求解步骤: 1)  根据已知的互斥关系,采用并查集建立连通集,分别记录每个连通集在两个监狱中的成员数目,记为v1, v2. 2)  采用动态规划算法,用布尔变量dp[

Leetcode 494 Target Sum 动态规划 背包+滚动数据

这是一道水题,作为没有货的水货楼主如是说. 题意:已知一个数组nums {a1,a2,a3,.....,an}(其中0<ai <=1000(1<=k<=n, n<=20))和一个数S c1a1c2a2c3a3......cnan = S, 其中ci(1<=i<=n)可以在加号和减号之中任选. 求有多少种{c1,c2,c3,...,cn}的排列能使上述等式成立. 例如: 输入:nums is [1, 1, 1, 1, 1], S is 3. 输出 : 5符合要求5种

活动选择的贪心算法与动态规划(未完成)

// greedy_algorithm.cpp : 定义控制台应用程序的入口点. // #include "stdafx.h" #include<iostream> #include<queue> using namespace std; #define NofActivity 11 int c[NofActivity + 1][NofActivity + 1]; int reme[NofActivity + 1][NofActivity + 1]; //活动的

求不相邻金币相加和的最大值--动态规划1

求不相邻金币相加和的最大值. 输入n个金币的金币面值(正数自定义),求这些金币不相邻和的最大值. 动态规划问题1 设f(n)为第n个金币数的最大值,f(0)=0,f(1)=a[1],输入的数组从下标为1开始. f(n)=max{a[n]+f(n-2),f(n-1)}. 代码如下: import java.util.Scanner; public class Jin_bi_zui_da_zhi { public static void main(String[] args) { Scanner s

[动态规划] 黑客的攻击 Hacker&#39;s CrackDown Uva 11825

抽象为数学模型就是,  取尽可能多的互不相交的子集 ,  使得每一个子集都能覆盖全集 #include <algorithm> #include <cstring> #include <cstdio> using namespace std; int n; int P[1000],cover[1000],f[1000]; int main(){ scanf("%d", &n); for (int i = 0; i < n;i++) {

Beauty Of algorithms(七)动态规划 钢条分割 矩阵链乘 最长公共子序列 最优二叉树

1.动态规划                动态规划的方法与方法类似,英文"dynamic programming",这里的programming不是程序的意思,而是一种表格法.都是通过组合子问题的解来解决原问题,分治方法将划分为互不相交的子问题,递归的求解子问题,再将它们的解组合起来求出原问题的解.与之相反动态规划应用于子问题的重叠情况,即不同的子问题具有公共的子问题,子问题的求解是递归进行 的,将其划分为更小的子问题,动态规划,每个子问题只求解一次,将其保存在表格中,从而无需每次求

Hdoj 1176 免费馅饼 【动态规划】

免费馅饼 Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others) Total Submission(s): 26110    Accepted Submission(s): 8905 Problem Description 都说天上不会掉馅饼,但有一天gameboy正走在回家的小径上,忽然天上掉下大把大把的馅饼.说来gameboy的人品实在是太好了,这馅饼别处都不掉,就掉落在他身旁的1

Fibonacci斐波拉契数列----------动态规划DP

n==10 20 30 40 50 46 体验一下,感受一下,运行时间 #include <stdio.h>int fib(int n){ if (n<=1)     return 1; else            return fib(n-1)+fib(n-2); }int main( ){ int n; scanf("%d",&n); printf("%d\n" ,fib(n) );} 先 n==10 20 30 40 50 46