Google Code Jam 2009, Round 1C C. Bribe the Prisoners (记忆化dp)

Problem

In a kingdom there are prison cells (numbered 1 to P) built to form a straight line segment. Cells number i and i+1 are adjacent, and prisoners in adjacent cells are called "neighbours." A wall with a window separates adjacent cells, and neighbours can communicate through that window.

All prisoners live in peace until a prisoner is released. When that happens, the released prisoner‘s neighbours find out, and each communicates this to his other neighbour. That prisoner passes it on to his other neighbour, and so on until they reach a prisoner with no other neighbour (because he is in cell 1, or in cell P, or the other adjacent cell is empty). A prisoner who discovers that another prisoner has been released will angrily break everything in his cell, unless he is bribed with a gold coin. So, after releasing a prisoner in cell A, all prisoners housed on either side of cell A - until cell 1, cell P or an empty cell - need to be bribed.

Assume that each prison cell is initially occupied by exactly one prisoner, and that only one prisoner can be released per day. Given the list of Q prisoners to be released in Qdays, find the minimum total number of gold coins needed as bribes if the prisoners may be released in any order.

Note that each bribe only has an effect for one day. If a prisoner who was bribed yesterday hears about another released prisoner today, then he needs to be bribed again.

Input

The first line of input gives the number of cases, NN test cases follow. Each case consists of 2 lines. The first line is formatted as

P Q

where P is the number of prison cells and Q is the number of prisoners to be released.
This will be followed by a line with Q distinct cell numbers (of the prisoners to be released), space separated, sorted in ascending order.

Output

For each test case, output one line in the format

Case #X: C

where X is the case number, starting from 1, and C is the minimum number of gold coins needed as bribes.

Limits

1 ≤ N ≤ 100
Q ≤ P
Each cell number is between 1 and P, inclusive.

Small dataset

1 ≤ P ≤ 100
1 ≤ Q ≤ 5

Large dataset

1 ≤ P ≤ 10000
1 ≤ Q ≤ 100

Sample

Input 
 
Output 
 
2
8 1
3
20 3
3 6 14
Case #1: 7
Case #2: 35

Note

In the second sample case, you first release the person in cell 14, then cell 6, then cell 3. The number of gold coins needed is 19 + 12 + 4 = 35. If you instead release the person in cell 6 first, the cost will be 19 + 4 + 13 = 36.

题目大意:

t 组测试数据,n个人在监狱,要放出m个人,每放出一个人,他周围的人(两边连续的直到碰到空的监狱或者尽头)都要贿赂1个钱,问最少的总花费

解题思路:

记忆化dp,dp(i,j) 表示从 编号 a[i] ~ a[j] 不包含 a[i] 与 a[j] 的子树的花费

状态转移方程 d[i][j]=min(dp(i,k)+dp(k,j)+(a[j]-a[i]-2),d[i][j])

注意,一开始添加哨兵,0号位与n+1号位

 1 void solve()
 2 {
 3     a[0]=0;a[m+1]=n+1;
 4     for(int i=0;i<=n;i++)
 5         dp[i][i+1]=0;
 6     for(int w=2;i+w<=m+1;i++)
 7     {
 8         for(int i=0;i+w<=m+1;i++)
 9         {
10             int j=i+w,t=inf;
11             for(int k=i+1;k<j;k++)
12                 t=min(t,dp[i][k]+dp[k][j]);
13             dp[i][j]=t+a[j]-a[i]-2;
14         }
15     }
16     cout<<dp[0][m+1]<<endl;
17 }
 1 #include"iostream"
 2 #include"cstdio"
 3 #include"cstring"
 4 #include"algorithm"
 5 using namespace std;
 6 const int inf=1e9;
 7 const int ms=110;
 8 int a[ms],dp[ms][ms],n,m,p;
 9 int solve(int i,int j)
10 {
11     if(dp[i][j]!=inf)
12         return dp[i][j];
13     if(i+1>=j)
14         return 0;
15     for(int k=i+1;k<j;k++)
16         dp[i][j]=min(solve(i,k)+solve(k,j)+(a[j]-a[i]-2),dp[i][j]);
17     return dp[i][j];
18 }
19 int main()
20 {
21     int t;
22     p=1;
23     cin>>t;
24     while(t--)
25     {
26         cin>>n>>m;
27         a[0]=0;a[m+1]=n+1;
28         for(int i=1;i<=m;i++)
29             cin>>a[i];
30         //fill(dp,dp+sizeof(dp)/sizeof(int),inf);  出错
31         for(int i=0;i<=m+1;i++)
32             for(int j=0;j<=m+1;j++)
33                 dp[i][j]=inf;
34         int ans=solve(0,m+1);
35         cout<<"Case #"<<p++<<": "<<ans<<endl;
36     }
37     return 0;
38 }

Google Code Jam 2009, Round 1C C. Bribe the Prisoners (记忆化dp)

时间: 2024-12-24 11:22:15

Google Code Jam 2009, Round 1C C. Bribe the Prisoners (记忆化dp)的相关文章

Google Code Jam 2016 Round 1C C

题意:三种物品分别有a b c个(a<=b<=c),现在每种物品各选一个进行组合.要求每种最和最多出现一次.且要求任意两个物品的组合在所有三个物品组合中的出现总次数不能超过n. 要求给出一个方案,使得我们能够生成的组合数最多. 分析: 首先我们可以简单的处理一种情况,就是c<=n的情况. 因为我们枚举出了所有组合,那么两物品的出现次数的最大值不会超过c,因为A种和B种的每对组合都会在其中出现c次,其余两个的组合出现次数更少. 所以这种情况一定不会超过n,我们只需要枚举所有组合即可. 然而

Google Code Jam 2014 Round 2回顾和分析

回顾 比赛开始网络就一直在抽风,不知道宿舍网渣还是有人攻击服务器.刷了n遍n久刷出了题目.提交A小case的时候眼睁睁看着时间过去,却提交不上,这破网.最后A题B题还是解决了,C题扫了一眼,读都没读,就奔D题去了,因为我看到了熟悉的trie这个单词,加之看到小case只有9分,判断小case应该比较容易.前面因为网络浪费了很多时间,加之从未编过trie的程序,只能临时上网翻书去学,最后D小这个可以很容易暴力解的问题也没编完. 最终的rank是13xx,考虑到在这次GCJ之前从未接触过编程竞赛,而

Google Code Jam 2014 Round 1B Problem B

二进制数位DP,涉及到数字的按位与操作. 查看官方解题报告 #include <cstdio> #include <cstdlib> #include <cstring> #include <iostream> using namespace std; #define MAX_LEN 50 long long A, B, K; int a[MAX_LEN], b[MAX_LEN], k[MAX_LEN]; long long memoize[MAX_LEN]

Google Code Jam 2016 Round 1B B

题意:给出两个数字位数相同,分别中间有若干位不知道,用问号表示.现在要求补全这两个数字,使得差值的绝对值最小,多解则取第一个数字的值最小的,再多解就取第二个数字最小的. 分析: 类似数位dp,但是很多状态可以直接得出最终解,个别状态需要状态转移. 我们从高位到低位依次确定两个数的每个位是几.一旦确定了两个数的一个位不一样,则可以立即将小的一方的后续问号全部写9,大的一方后续问号全部写0.这样才能让差值最小. 那我们观察每个位的时候要如何确定其值呢?分如下几种情况. 1.两个数的该位都是问号,那么

2015 Google code jam Qualification Round B 枚举 + 贪心

题意:给你一个无穷长的数列 和一些非 0 的值,可以进行两种操作. 1)数列中所有大于1的值 都减1 2)从 a[i] 中取出任意的值分给任意人. 问你最少执行多少步能使的 数列全为0. 解题思路:枚举最大的a[i].大于 a[i]的部分都分出去. 解题代码: 1 // File Name: b.cpp 2 // Author: darkdream 3 // Created Time: 2015年04月11日 星期六 23时16分58秒 4 5 #include<vector> 6 #incl

Google Code Jam 2015 Round 1A Mushroom Monster 水

题意:每10秒扫描一下盘子,查看盘子里面的面包个数,问你主角用两种吃法可能吃得的最少的面包. 1)任意吃. 2)每秒以恒定速度. 解题思路:暴力,找差值. 解题代码: 1 // File Name: a.cpp 2 // Author: darkdream 3 // Created Time: 2015年04月18日 星期六 09时52分04秒 4 5 #include<vector> 6 #include<list> 7 #include<map> 8 #includ

Google Code Jam 2015 Round 1A Haircut 二分

题意:给你每个理发师的理发时间,问你排在队列中的第N个位置,问你应该被哪个理发师剪发. 解题思路:二分时间,看这个时间到第几个人理发了,然后找到临界值,看这个值的时候有那些理发师接待了新旅客的,即可找到那个理发师. 解题代码: 1 // File Name: b.sample.cpp 2 // Author: darkdream 3 // Created Time: 2015年04月18日 星期六 09时05分30秒 4 5 #include<vector> 6 #include<lis

2015 Google code jam Qualification Round A 水

题意:给你一个序列 从 0-n  初始位置为0 ,只能从 i 走到 i+1  你必要有的人数 >= i+1  ,每个位置有a[i]个人,问你走到 n 还需要多少个人. 解题思路:暴力 解题代码: 1 // File Name: a.cpp 2 // Author: darkdream 3 // Created Time: 2015年04月11日 星期六 23时06分57秒 4 5 #include<vector> 6 #include<list> 7 #include<

Google Code Jam 2019 Round 1A 题解

A. Alien Rhyme 题意: 思路:将字符反向插入一颗Trie,然后自下而上的贪心即可,即先选后缀长的,再选后缀短的. 实现: 1 #include <iostream> 2 #include <cstdio> 3 #include <cstdlib> 4 #include <iomanip> 5 6 #include <vector> 7 #include <cstring> 8 #include <string>