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
#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 -密室的更多相关文章
- 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 ...
- CH Round #53 -GCD Path
描述 给定一张N个点的有向图,点i到点j有一条长度为 i/(gcd(i,j))的边.有Q个询问,每个询问包含两个数x和y,求x到y的最短距离. 输入格式 第一行包含两个用空格隔开的整数,N和Q. 接下 ...
- Educational Codeforces Round 53 (Rated for Div. 2) (前五题题解)
这场比赛没有打,后来补了一下,第五题数位dp好不容易才搞出来(我太菜啊). 比赛传送门:http://codeforces.com/contest/1073 A. Diverse Substring ...
- CH Round #52 还教室[线段树 方差]
还教室 CH Round #52 - Thinking Bear #1 (NOIP模拟赛) [引子]还记得 NOIP 2012 提高组 Day2 中的借教室吗?时光飞逝,光阴荏苒,两年过去了,曾经借教 ...
- CH Round #72树洞[二分答案 DFS&&BFS]
树洞 CH Round #72 - NOIP夏季划水赛 描述 在一片栖息地上有N棵树,每棵树下住着一只兔子,有M条路径连接这些树.更特殊地是,只有一棵树有3条或更多的路径与它相连,其它的树只有1条或2 ...
- CH Round #30 摆花[矩阵乘法]
摆花 CH Round #30 - 清明欢乐赛 背景及描述 艺术馆门前将摆出许多花,一共有n个位置排成一排,每个位置可以摆花也可以不摆花.有些花如果摆在相邻的位置(隔着一个空的位置不算相邻),就不好看 ...
- contesthunter CH Round #64 - MFOI杯水题欢乐赛day1 solve
http://www.contesthunter.org/contest/CH Round %2364 - MFOI杯水题欢乐赛 day1/Solve Solve CH Round #64 - MFO ...
- CH Round #17 舞动的夜晚
舞动的夜晚 CH Round #17 描述 L公司和H公司举办了一次联谊晚会.晚会上,L公司的N位员工和H公司的M位员工打算进行一场交际舞.在这些领导中,一些L公司的员工和H公司的员工之间是互相认识的 ...
- CH Round #45 能量释放
能量释放 CH Round #45 - alan有一些陷阱 III 题目描述 alan得到一块由个能量晶体构成的矿石,对于矿石中的每一个能量晶体,如果用化学物质刺激某一个能量晶体,就能使它释放能量. ...
随机推荐
- URAL 2034 : Caravans
Description Student Ilya often skips his classes at the university. His friends criticize him for ...
- 深入理解C#第二版笔记
基础知识 委托 如果代码想要执行操作,但不知道操作细节,一般可以使用委托.例如:Thread类之所以知道要在一个新线程里运行什么,唯一的原因就是在启动新线程时,向它提供了一个ThreadStart委托 ...
- node.js + express(ejs) + mongodb(mongoose) 增删改实例
MongoDB 安装步骤总结: 1.解压目录到d盘 mongodb 2.安装目录的下新建文件mongo.config文件 ##store data here dbpath=D:\mongodb\dat ...
- 怎样把HTC G7的内存扩展到2GB
介绍 HTC G7的内部存储只有148M,两年前买它的时候,android应用大多比较小巧,148M已经足够用了.随着android版本的不断升级,应用变得越来越臃肿,G7也变得越来越吃力.就我个人而 ...
- [React] React Router: setRouteWillLeaveHook
setRouteWillLeaveHook provides a method for us to intercept a route change before leaving the curren ...
- [Angular 2] Build a select dropdown with *ngFor in Angular 2
We want the start-pipe more flexable to get param, so when using it, we pass a second param as statu ...
- Linux CentOS PhpMyAdmin安装
安装好PHP,Apache和MySQL程序后,为了管理MySQL数据库,我们需要安装phpMyAdmin程序.下面是关于如何在centos安装phpMyAdmin程序的方法.1.管理员root身份登录 ...
- .net framework 注册到IIS上
首先要安装好所需的IIS版本和.net framework 各版本,注册方式如下: 1.1:C:\WINDOWS\Microsoft.NET\Framework\v1.1.4322\aspnet_re ...
- 模板模式(Template)
行为型:Template(模板模式) 作为一个曾经爱好写文章,但是不太懂得写文章的人,我必须承认,开头是个比较难的起步. 模板模式常规定义:模板模式定义了一个算法步骤,把实现延迟到子类. 事实上模板模 ...
- hdu5353
模拟,,, 每个人有一些糖果,每两个人之间只能给一个糖果,问最后是否能让所有人的糖果数量相同,只要确定一个糖果的流向其他的就能够确定. 马虎了,卡了好几天,心塞塞的... #include<io ...