描述

有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

 #include<cstdio>

 #include<cstdlib>

 #include<cmath>

 #include<cstring>

 #include<algorithm>

 #include<iostream>

 #include<vector>

 #include<map>

 #include<set>

 #include<queue>

 #include<string>

 #define inf 1000000000

 #define maxn 10000000

 #define maxm 500+100

 #define eps 1e-10

 #define ll long long

 #define pa pair<int,int>

 #define for0(i,n) for(int i=0;i<=(n);i++)

 #define for1(i,n) for(int i=1;i<=(n);i++)

 #define for2(i,x,y) for(int i=(x);i<=(y);i++)

 #define for3(i,x,y) for(int i=(x);i>=(y);i--)

 #define mod 1000000007

 using namespace std;

 inline int read()

 {

     int x=,f=;char ch=getchar();

     while(ch<''||ch>''){if(ch=='-')f=-;ch=getchar();}

     while(ch>=''&&ch<=''){x=*x+ch-'';ch=getchar();}

     return x*f;

 }
struct rec1{int x,y,z;}a[],b[];
struct rec2{int x,y,z,w;}q[maxn];
int n; int main() { freopen("input.txt","r",stdin); freopen("output.txt","w",stdout); n=read();
for1(i,n)a[i].x=read();
for1(i,n)a[i].y=read();
for1(i,n)b[i].x=read();
for1(i,n)b[i].y=read();
for1(i,n)b[i].z=read();
int l=,r=;
q[++r].x=read(),q[r].y=read(),q[r].z=read(),q[r].w=;
int ans=q[r].x+q[r].y+q[r].z;
while(l!=r)
{
rec2 now=q[++l];if(l==maxn)break;
for1(i,n)
if((((now.w)&(<<(i-)))==)&&(max(a[i].x-now.x,)+max(a[i].y-now.y,)<=now.z))
{
q[++r].x=max(now.x-a[i].x,)+b[i].x;if(r==maxn)r=;
q[r].y=max(now.y-a[i].y,)+b[i].y;
q[r].z=now.z-max(a[i].x-now.x,)-max(a[i].y-now.y,)+b[i].z;
q[r].w=now.w+(<<(i-));
if(q[r].x+q[r].y+q[r].z>ans)ans=q[r].x+q[r].y+q[r].z;
}
}
printf("%d\n",ans); return ; }

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

 #include <cmath>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
#define N 50000 + 5 int n, x, y, z, ans, door[][], key[][];
bool Open[N], Vis[N]; inline void dfs(int state, int r, int g, int w)
{
if (Vis[state]) return ;
ans = max(ans, r + g + w);
for (int i = ; i <= n; i ++)
if (!Open[i])
{
int _r = r - door[i][];
int _g = g - door[i][];
int _w = w + min(_r, ) + min(_g, );
if (_w < ) continue ;
_r = max(_r, ) + key[i][];
_g = max(_g, ) + key[i][];
_w += key[i][];
Open[i] = ;
dfs(state ^ ( << i - ), max(_r, ), max(_g, ), _w);
Open[i] = ;
}
Vis[state] = ;
} int main()
{
scanf("%d", &n);
for (int i = ; i < ; i ++)
for (int j = ; j <= n; j ++)
scanf("%d", door[j] + i);
for (int i = ; i < ; i ++)
for (int j = ; j <= n; j ++)
scanf("%d", key[j] + i);
scanf("%d%d%d", &x, &y, &z);
dfs(, x, y, z);
printf("%d\n", ans);
return ;
}

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

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

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

这是一种贪心的思想。

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

代码3:lyd的神代码

 #include<cstring>
#include<cstdio>
#include<iostream>
#define fo(i,n) for(int i=0;i<n;i++)
using namespace std;
const int N=;
int dR[N],dG[N],rR[N],rG[N],rW[N],ky[N],n,f[][],z;
int main(){
freopen("input.txt", "r",stdin);
freopen("output.txt","w",stdout);
cin>>n;
fo(i,n) cin>>dR[i];
fo(i,n) cin>>dG[i];
fo(i,n) cin>>rR[i];
fo(i,n) cin>>rG[i];
fo(i,n) cin>>rW[i];
cin>>ky[]>>ky[]>>ky[];
int sum=ky[]+ky[]+ky[];
memset(f,-,sizeof f);
f[][ky[]]=ky[];
fo(i,<<n){
int k0=ky[],k1=ky[],r=sum;
fo(j,n)
if(i>>j&){
k0+=rR[j];
r+=rR[j]+rG[j]+rW[j]-dR[j]-dG[j];
}
for(int j=;j<=k0;j++){
if(f[i][j]==-) continue;
int fr=f[i][j];
int k=r-fr-j;
fo(l,n){
if(i>>l&) continue;
int r=max(,dR[l]-j),g=max(,dG[l]-k);
int &q=f[i|(<<l)][max(,j-dR[l])+rR[l]];
if(fr>=r+g)
q=max(q,fr-r-g+rW[l]);
}
z=max(z,j+k+fr);
}
}
cout<<z<<endl;
}

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

  1. CH Round #53 -【Nescafé 32】杯NOIP模拟赛

    A.GCD Path http://ch.ezoj.tk/contest/CH%20Round%20%2353%20-%E3%80%90Nescaf%C3%A9%2032%E3%80%91%E6%9D ...

  2. CH Round #53 -GCD Path

    描述 给定一张N个点的有向图,点i到点j有一条长度为 i/(gcd(i,j))的边.有Q个询问,每个询问包含两个数x和y,求x到y的最短距离. 输入格式 第一行包含两个用空格隔开的整数,N和Q. 接下 ...

  3. Educational Codeforces Round 53 (Rated for Div. 2) (前五题题解)

    这场比赛没有打,后来补了一下,第五题数位dp好不容易才搞出来(我太菜啊). 比赛传送门:http://codeforces.com/contest/1073 A. Diverse Substring ...

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

    还教室 CH Round #52 - Thinking Bear #1 (NOIP模拟赛) [引子]还记得 NOIP 2012 提高组 Day2 中的借教室吗?时光飞逝,光阴荏苒,两年过去了,曾经借教 ...

  5. CH Round #72树洞[二分答案 DFS&&BFS]

    树洞 CH Round #72 - NOIP夏季划水赛 描述 在一片栖息地上有N棵树,每棵树下住着一只兔子,有M条路径连接这些树.更特殊地是,只有一棵树有3条或更多的路径与它相连,其它的树只有1条或2 ...

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

    摆花 CH Round #30 - 清明欢乐赛 背景及描述 艺术馆门前将摆出许多花,一共有n个位置排成一排,每个位置可以摆花也可以不摆花.有些花如果摆在相邻的位置(隔着一个空的位置不算相邻),就不好看 ...

  7. contesthunter CH Round #64 - MFOI杯水题欢乐赛day1 solve

    http://www.contesthunter.org/contest/CH Round %2364 - MFOI杯水题欢乐赛 day1/Solve Solve CH Round #64 - MFO ...

  8. CH Round #17 舞动的夜晚

    舞动的夜晚 CH Round #17 描述 L公司和H公司举办了一次联谊晚会.晚会上,L公司的N位员工和H公司的M位员工打算进行一场交际舞.在这些领导中,一些L公司的员工和H公司的员工之间是互相认识的 ...

  9. CH Round #45 能量释放

    能量释放 CH Round #45 - alan有一些陷阱 III 题目描述 alan得到一块由个能量晶体构成的矿石,对于矿石中的每一个能量晶体,如果用化学物质刺激某一个能量晶体,就能使它释放能量. ...

随机推荐

  1. sublime3 使用技巧

    Ctrl+O(Command+O)可以实现头文件和源文件之间的快速切换 Ctrl+Shift+T可以打开之前关闭的tab页,这点同chrome是一样的 Ctrl+R定位函数:Ctrl+G定位到行: 插 ...

  2. [原创+实战+钓鱼]setoolkit+映射

    所需工具:setoolkit,花生壳 (此方法主要针对没有服务器,没有空间的攻击者.有服务器或者空间可以直接上传setoolkit的生成源码到服务器或者空间.) 1.setoolkit克隆一个站点 | ...

  3. c++中基本的语法问题

    的输出是? 答案:构造函数的初始化列表 字符串转化为整形的代码: enum Status{ kValid = 0,kInvalid }; int g_nStatus = kValid; int Str ...

  4. getChars的使用方法

    <%@ page contentType="text/html; charset=gb2312" %> <%@ page import="java.ut ...

  5. 用python演示一个简单的AST(抽象语法树)

    如果对'a + 3 * b'进行解释,当中a=2,b=5 代码非常easy,就不再进行具体的解释了. Num = lambda env, n: n Var = lambda env, x: env[x ...

  6. IOS成长之路-Nsstring中搜索方法rangeOfString

    NSString *str1 = @"can you \n speak English"; NSString *str = @"\n"; //在str1这个字符 ...

  7. Mysql数据库的mysql Schema 究竟有哪些东西&amp; 手工注入的基础要领

    #查看数据库版本号 mysql> select @@version; +------------+ | @@version  | +------------+ | 5.5.16-log | +- ...

  8. LF will be replaced by CRLF问题解决方法

    [GIT] warning: LF will be replaced by CRLF问题解决方法 开发环境: 操作系统: windows xp ruby 1.9.2 rails 3.1.3 git v ...

  9. Linux命令之文件与用户权限

    1.文件管理 在Linux里,任何软件和I/O设备都被视为文件.Linux中的文件名最大支持256个字符,分别可以用A-Z.a-z.0-9等字符来命名. 和Windows不同,Linux中文件是区分大 ...

  10. 第一篇博客关于Log4net的配置记录

    说明:本程序演示如何利用log4net记录程序日志信息.log4net是一个功能著名的开源日志记录组件.利用log4net可以方便地将日志信息记录到文件.控制台.Windows事件日志和数据库(包括M ...