CH Round #53 -密室

描述

有N个密室,3种钥匙(红色,绿色,白色)和2种锁(红色,绿色),红色钥匙只能开红色的锁,绿色钥匙只能开绿色的锁,白色钥匙可以开红色的锁和绿 色的锁,一把钥匙使用一次之后会被扔掉。每个密室由一扇门锁着,上面锁着一些红色和绿色的锁,房间里面放着一些红色、绿色和白色的钥匙,打开密室你将拿走 这些钥匙。你可以以任意顺序打开密室,但是同一个密室只能打开一次。初始你已经有了一些钥匙了,现在你要进行决策,使得最终剩下的钥匙尽量的多,注意,你 不一定要打开所有的房间,你可以在任意时刻结束。输出你最多能有几把钥匙。

输入格式

第一行一个整数N,表示有N个密室。
第二行N个整数,第i个数表示第i扇门上有ai把红色的锁。
第三行N个整数,第i个数表示第i扇门上有bi把绿色的锁。
第四行N个整数,第i个数表示第i个密室有ci把红色的钥匙。
第五行N个整数,第i个数表示第i个密室有di把绿色的钥匙。
第六行N个整数,第i个数表示第i个密室有ei把白色的钥匙。
第七行三个整数k0,k1,k2,依次表示初始你拥有的红色、绿色、白色钥匙的数量。

输出格式

输出一个整数,表示你最多能有几把钥匙。

样例输入

3
1 2 3
0 4 9
0 0 10
0 8 9
1 0 8
3 1 2

样例输出

8

数据范围与约定

  • 对于40%的数据,满足N<=8。
  • 对于100%的数据,满足N<=14,0<=ai,bi,ci,di,ei,k0,k1,k2<=10。

题解:
刚才在与iwtwiioi的讨论中又有了新的发现,现在来写一下详细的题解。
考虑到打开门的集合一定,钥匙总数一定是一定的,因为一把钥匙开一把锁,那么是否可以直接以开门集合为状态进行转移呢?
答案是否定的。因为钥匙总数是一定的并不代表着红、蓝、白这三种钥匙各自的数量相同,比如你有5 0 9 能去打开0 10的门吗? 而4 1 9就可以。
这种情况为什么会发生?是因为开门顺序不同导致的。比如:
门1  开5 0  得0 0 2
门2  开2 0  的10 0 0
刚开始有 3 1 2
如果先开1,则有 0 1 2,再开2,有10 1 0    
如果先开2,则有11 1 2,再开2,有6 1 4
这样就出现了不同。
这样的话,如果后面还有
门3 开0 5 得 10 10 10
这样按1-2的顺序无法打开此门,显然不会是最优解

如果按2-1来打开,则可以打开门3,得到最优解。

所以,不能单单以经过门的集合,而应该加入红、蓝、白数量作为状态,这样的话那么就只能爆搜了。。。

BFS应该可过,数组开1000W。DFS可能由于需要调用系统栈而使时间变长,导致超时。
代码1:我的BFS

 1 #include<cstdio>
 2
 3 #include<cstdlib>
 4
 5 #include<cmath>
 6
 7 #include<cstring>
 8
 9 #include<algorithm>
10
11 #include<iostream>
12
13 #include<vector>
14
15 #include<map>
16
17 #include<set>
18
19 #include<queue>
20
21 #include<string>
22
23 #define inf 1000000000
24
25 #define maxn 10000000
26
27 #define maxm 500+100
28
29 #define eps 1e-10
30
31 #define ll long long
32
33 #define pa pair<int,int>
34
35 #define for0(i,n) for(int i=0;i<=(n);i++)
36
37 #define for1(i,n) for(int i=1;i<=(n);i++)
38
39 #define for2(i,x,y) for(int i=(x);i<=(y);i++)
40
41 #define for3(i,x,y) for(int i=(x);i>=(y);i--)
42
43 #define mod 1000000007
44
45 using namespace std;
46
47 inline int read()
48
49 {
50
51     int x=0,f=1;char ch=getchar();
52
53     while(ch<‘0‘||ch>‘9‘){if(ch==‘-‘)f=-1;ch=getchar();}
54
55     while(ch>=‘0‘&&ch<=‘9‘){x=10*x+ch-‘0‘;ch=getchar();}
56
57     return x*f;
58
59 }
60 struct rec1{int x,y,z;}a[20],b[20];
61 struct rec2{int x,y,z,w;}q[maxn];
62 int n;
63
64 int main()
65
66 {
67
68     freopen("input.txt","r",stdin);
69
70     freopen("output.txt","w",stdout);
71
72     n=read();
73     for1(i,n)a[i].x=read();
74     for1(i,n)a[i].y=read();
75     for1(i,n)b[i].x=read();
76     for1(i,n)b[i].y=read();
77     for1(i,n)b[i].z=read();
78     int l=0,r=0;
79     q[++r].x=read(),q[r].y=read(),q[r].z=read(),q[r].w=0;
80     int ans=q[r].x+q[r].y+q[r].z;
81     while(l!=r)
82     {
83         rec2 now=q[++l];if(l==maxn)break;
84         for1(i,n)
85          if((((now.w)&(1<<(i-1)))==0)&&(max(a[i].x-now.x,0)+max(a[i].y-now.y,0)<=now.z))
86          {
87           q[++r].x=max(now.x-a[i].x,0)+b[i].x;if(r==maxn)r=0;
88           q[r].y=max(now.y-a[i].y,0)+b[i].y;
89           q[r].z=now.z-max(a[i].x-now.x,0)-max(a[i].y-now.y,0)+b[i].z;
90           q[r].w=now.w+(1<<(i-1));
91           if(q[r].x+q[r].y+q[r].z>ans)ans=q[r].x+q[r].y+q[r].z;
92          }
93     }
94     printf("%d\n",ans);
95
96     return 0;
97
98 }

代码2:只以经过的门的集合为状态

 1 #include <cmath>
 2 #include <cstdio>
 3 #include <cstring>
 4 #include <iostream>
 5 #include <algorithm>
 6 using namespace std;
 7 #define N 50000 + 5
 8
 9 int n, x, y, z, ans, door[21][2], key[21][3];
10 bool Open[N], Vis[N];
11
12 inline void dfs(int state, int r, int g, int w)
13 {
14     if (Vis[state]) return ;
15     ans = max(ans, r + g + w);
16     for (int i = 1; i <= n; i ++)
17         if (!Open[i])
18         {
19             int _r = r - door[i][0];
20             int _g = g - door[i][1];
21             int _w = w + min(_r, 0) + min(_g, 0);
22             if (_w < 0) continue ;
23             _r = max(_r, 0) + key[i][0];
24             _g = max(_g, 0) + key[i][1];
25             _w += key[i][2];
26             Open[i] = 1;
27             dfs(state ^ (1 << i - 1), max(_r, 0), max(_g, 0), _w);
28             Open[i] = 0;
29         }
30     Vis[state] = 1;
31 }
32
33 int main()
34 {
35     scanf("%d", &n);
36     for (int i = 0; i < 2; i ++)
37         for (int j = 1; j <= n; j ++)
38             scanf("%d", door[j] + i);
39     for (int i = 0; i < 3; i ++)
40         for (int j = 1; j <= n; j ++)
41             scanf("%d", key[j] + i);
42     scanf("%d%d%d", &x, &y, &z);
43     dfs(0, x, y, z);
44     printf("%d\n", ans);
45     return 0;
46 }

刚才orz了lyd的代码:发现他是这样做的状态:

f[i][j]表示经过门的集合为i,红钥匙数为 j 时白钥匙最多有多少,因为我们固定了红钥匙,所以白钥匙的数量越多越好。

因为它既可以当红的,也可以当蓝的使,白钥匙最多的时候一定可以打开所有白钥匙不是最多的时候能打开的门,而且还能打开一些原来打不开的门。见上面的例子。

这是一种贪心的思想。

然后,状态的转移就变的十分简单了,简直不能再orz。

代码3:lyd的神代码

 1 #include<cstring>
 2 #include<cstdio>
 3 #include<iostream>
 4 #define fo(i,n) for(int i=0;i<n;i++)
 5 using namespace std;
 6 const int N=15;
 7 int dR[N],dG[N],rR[N],rG[N],rW[N],ky[N],n,f[20000][200],z;
 8 int main(){
 9     freopen("input.txt", "r",stdin);
10     freopen("output.txt","w",stdout);
11     cin>>n;
12     fo(i,n) cin>>dR[i];
13     fo(i,n) cin>>dG[i];
14     fo(i,n) cin>>rR[i];
15     fo(i,n) cin>>rG[i];
16     fo(i,n) cin>>rW[i];
17     cin>>ky[0]>>ky[1]>>ky[2];
18     int sum=ky[0]+ky[1]+ky[2];
19     memset(f,-1,sizeof f);
20     f[0][ky[0]]=ky[2];
21     fo(i,1<<n){
22         int k0=ky[0],k1=ky[1],r=sum;
23         fo(j,n)
24             if(i>>j&1){
25                 k0+=rR[j];
26                 r+=rR[j]+rG[j]+rW[j]-dR[j]-dG[j];
27             }
28         for(int j=0;j<=k0;j++){
29             if(f[i][j]==-1) continue;
30             int fr=f[i][j];
31             int k=r-fr-j;
32             fo(l,n){
33                 if(i>>l&1) continue;
34                 int r=max(0,dR[l]-j),g=max(0,dG[l]-k);
35                 int &q=f[i|(1<<l)][max(0,j-dR[l])+rR[l]];
36                 if(fr>=r+g)
37                     q=max(q,fr-r-g+rW[l]);
38             }
39             z=max(z,j+k+fr);
40         }
41     }
42     cout<<z<<endl;
43 }

时间: 2024-10-18 16:34:06

CH Round #53 -密室的相关文章

CH Round #45 能量释放

能量释放 CH Round #45 - alan有一些陷阱 III 题目描述 alan得到一块由个能量晶体构成的矿石,对于矿石中的每一个能量晶体,如果用化学物质刺激某一个能量晶体,就能使它释放能量. 它的能量释放强度与晶体本身的能量值以及能量晶体的位置有关. 为了方便研究,alan做了如下的定义. 能量集:一块矿石中的第个能量晶体到第个能量晶体(包含和,)构成的集合. 能量储存点:对于一块矿石中的能量晶体和,若有,则称是能量储存点. 能量释放点:在一个能量集中,若存在一个能量晶体,使得除它之外的

CH Round #17 舞动的夜晚

舞动的夜晚 CH Round #17 描述 L公司和H公司举办了一次联谊晚会.晚会上,L公司的N位员工和H公司的M位员工打算进行一场交际舞.在这些领导中,一些L公司的员工和H公司的员工之间是互相认识的,这样的认识关系一共有T对.舞会上,每位员工会尝试选择一名Ta认识的对方公司的员工作为舞伴,并且每位员工至多跳一支舞.完成的交际舞的数量越多,晚会的气氛就越热烈.顾及到晚会的气氛,员工们希望知道,哪些员工之间如果进行了交际舞,就会使整场晚会能够完成的交际舞的最大数量减小. 输入格式 第一行三个整数N

CH Round #52 还教室[线段树 方差]

还教室 CH Round #52 - Thinking Bear #1 (NOIP模拟赛) [引子]还记得 NOIP 2012 提高组 Day2 中的借教室吗?时光飞逝,光阴荏苒,两年过去了,曾经借教室的同学们纷纷归还自己当初租借的教室.请你来解决类似于借教室的另一个问题.[问题描述]在接受借教室请求的 n 天中,第 i 天剩余的教室为 a i 个.作为大学借教室服务的负责人,你需要完成如下三种操作共 m 次:① 第 l 天到第 r 天,每天被归还 d 个教室.② 询问第 l 天到第 r 天教室

CH Round #30 摆花[矩阵乘法]

摆花 CH Round #30 - 清明欢乐赛 背景及描述 艺术馆门前将摆出许多花,一共有n个位置排成一排,每个位置可以摆花也可以不摆花.有些花如果摆在相邻的位置(隔着一个空的位置不算相邻),就不好看了.假定每种花数量无限,求摆花的方案数. 输入格式 输入有1+m行,第一行有两个用空格隔开的正整数n.m,m表示花的种类数.接下来的m行,每行有m个字符1或0,若第i行第j列为1,则表示第i种花和第j种花不能排在相邻的位置,输入保证对称.(提示:同一种花可能不能排在相邻位置). 输出格式 输出只有一

CH Round #57 - Story of the OI Class 凯撒密码

很有意思的一道题目 考场上想的是HASH成一个整数,把末位asicc码值*1,依次乘*10,得到一个整数,然后利用等差性.唯一性快排Nlogn乱搞的 证明如下: 对于明文abcde 密文 bcdef 有(a-b)*10000+(b-c)*1000+(c-d)*100+(d-f)*10+(e-f)*1=一个常数 这个常数我们可以预处理出来,对于任意的f[a,b],a,b属于小写字母,我们都可以预处理出来其值 好吧就是这个考场上写挂了 预处理出来之后依次排序维护标号然后O(n)一遍过就好,哎傻了 C

【题解】CH Round #61 取数游戏

取数游戏 CH Round #61 - 「Adera 10」冬令营热身赛 描述 SJY和CYF在玩一个取数游戏.他们将1~n分别写在n张纸上,随机排成一排,约定SJY先取,只能取走最边上的两张纸之一,然后CYF取:以此循环下去,取到1的人获胜.假设SJY和CYF足够聪明,求SJY获胜的概率. 输入 一个整数n 输出 SJY获胜的概率,保留最简分数形式(若为1,则输出1/1:若为0,则输出0/1). 样例 样例输入1 2 样例输出1 1/1 样例输入2 3 样例输出2 2/3 数据范围与约定 40

CH Round #56 - 国庆节欢乐赛解题报告

最近CH上的比赛很多,在此会全部写出解题报告,与大家交流一下解题方法与技巧. T1 魔幻森林 描述 Cortana来到了一片魔幻森林,这片森林可以被视作一个N*M的矩阵,矩阵中的每个位置上都长着一棵树,其中一些树上结有能够产生能量的魔力水果.已知每个水果的位置(Xi,Yi)以及它能提供的能量Ci.然而,魔幻森林在某些时候会发生变化:(1) 有两行树交换了位置.(2) 有两列树交换了位置.当然,树上结有的水果也跟随着树一起移动.不过,只有当两行(列)包含的魔力水果数都大于0,或者两行(列)都没有魔

CH Round #54 - Streaming #5 (NOIP模拟赛Day1)解题报告

最近参加了很多CH上的比赛呢~Rating--了..题目各种跪烂.各种膜拜大神OTZZZ T1珠 描述 萌蛋有n颗珠子,每一颗珠子都写有一个数字.萌蛋把它们用线串成了环.我们称一个数字串是有趣的,当且仅当它的第1位是2,且除了第1位以外的每一位都是3.例如,2,233,2333333都是有趣的数字串.现在,你可以从这串珠子的任意一颗开始读,沿着顺时针或逆时针方向,到任意一颗珠子停止.这样,你就可以读出一个数字串来.萌蛋想知道,所有能读出的有趣的数字串当中,最长的是哪一个数字串.当然,你也可能读不

CH Round #53-数据备份

描述 已知有N座办公楼位于同一条街上.你决定给这些办公楼配对(两个一组).每一对办公楼可以通过在这两个建筑物之间铺设网络电缆使得它们可以互相备 份.然而,网络电缆的费用很高.当地电信公司仅能为你提供K条网络电缆,这意味着你仅能为K对办公楼(或总计2K个办公楼)安排备份.任一个办公楼都属于 唯一的配对组(换句话说,这2K个办公楼一定是相异的). 此外,电信公司需按网络电缆的长度(公里数)收费.因而,你需要选择这K对办公楼使得电缆的总长度尽可能短.换句话说,你需要选择这K对办公楼,使得每一 对办公楼