题目
SJTU 1329 聚餐
洛谷 P2622 关灯问题II
洛谷 P1171 售货员的难题(待解决)
Storm in Lover //2018.7.22测试题
Description
为了庆祝机考,ACM班的m个同学决定去聚餐。
到了餐厅以后,他们发现一共有n个可供选择的菜(编号为1,2,⋯, n),所以每个同学都向负责点菜的班长大人提出了一些要求。比如,一个同学表示,他一定要吃辣;另一个同学表示,他不能看到维生素C。当然,要满足所有人的所有要求是很难做到的,因此只要有至少一个要求被满足,这个同学就会开心的去吃饭。
现在问题来了:班长是否能选择一些菜,使得所有人都能开心?
Input Format
第一行是一个正整数t,表示数据组数。每一组数据之间有一行空行。
对于一组数据,第一行有两个正整数n, m,用空格隔开。接下来有m行,每行有不超过n个整数,中间用空格隔开。
对于第i行的某个整数,如果是正整数k,表示同学i一定要吃编号为k的菜;如果是负整数-k,表示同学i不能忍受餐桌上有编号为k的菜。
Output Format
如果能够使所有人都开心,则输出”Bingo!”,否则输出”Sigh…”。
每组数据的输出结果占一行。
Sample Input
2
3 5
1 -2 3
-3
-1 3
1 3
-2 -3
3 5
-1 -2
1 -2
1 -2
1
1 2 3
Sample Output
Sigh…
Bingo!
Constraints
1 <= t <= 5;
1 <= n <= 20;
1 <= m <= 60
题目分析:
转载:http://www.cnblogs.com/LonelyRyan/p/8429968.html
现有n盏灯,以及m个按钮。每个按钮可以同时控制这n盏灯——按下了第i个按钮,对于所有的灯都有一个效果。按下i按钮对于第j盏灯,是下面3中效果之一:如果a[i][j]为1,那么当这盏灯开了的时候,把它关上,否则不管;如果为-1的话,如果这盏灯是关的,那么把它打开,否则也不管;如果是0,无论这灯是否开,都不管。
现在这些灯都是开的,给出所有开关对所有灯的控制效果,求问最少要按几下按钮才能全部关掉。
输入输出格式
输入格式:
前两行两个数,n m
接下来m行,每行n个数,a[i][j]表示第i个开关对第j个灯的效果。
输出格式:
一个整数,表示最少按按钮次数。如果没有任何办法使其全部关闭,输出-1
输入样例#1
3
2
1 0 1
-1 1 0
输出样例#1
2
说明
对于20%数据,输出无解可以得分。
对于20%数据,n<=5
对于20%数据,m<=20
上面的数据点可能会重叠。
对于100%数据 n<=10,m<=100
题目分析:
转载:https://www.luogu.org/blog/niiick/solution-p2622
海未面前现在有 n 个靶子。按照绘里的指示,海未需要把这 n 个靶子全部射穿才行。
一开始,海未的精力为 m,力度为 a。每射穿一个靶子,海未对弓的熟练度就会上升,此时
力度会增加 b。
每个靶子都有一个单独的耐久度 d[i],每次受到海未的攻击,靶子的耐久度都会减少海未当
前的力度的值。当靶子的耐久度为 0 或 0 以下时,靶子被破坏。但是,如果海未在一次射箭
后并没有射穿这个靶子,海未的精力会减少 c[i]。如果海未通过一次射箭破坏了靶子,她的
精力不会受到影响。
海未可以自由地选择射靶子的顺序。请问,海未是否能够通过合理地安排射靶子的顺序,使
得她能够将这些靶子全部射穿?如果能,她完成任务后最多能省下多少精力?如果不能,她
最多可以射穿多少个靶子?
输入格式
输入的第一行为四个正整数 n,m,a,b。
接下来 n 行,每行两个正整数 c[i],d[i]。
输出格式
输出的第一行仅包含一个字符串。请回答海未酱是否能完成全部射穿靶子的任务。如果可以
完成,输出“Yes”。如果不能完成,输出“No” 。(两者均不包括引号)
第二行仅包含一个正整数。若第一行为“Yes”,则你应输出所剩的最多精力值;若第一行为
“No”,则你应输出最多能射穿的靶子数。
样例输入:
2 10 1 1
1 4
1 6
样例输出:
Yes
5
数据范围:
对于 30%的数据,n<=6。
对于 50%的数据,n<=9。
对于 70%的数据,n<=14。
对于 100%的数据,n<=21;1<=a,b,c,d<=32767。
题目分析
本题给出了数据范围,我们发现n最大只有21,这意味着什么?我们可以考虑状态压缩!另外题目中提到的求所剩精力的最大值,并且可以随便按顺序去打,都在提示着我们可以用状压DP去做。
不过考场中很有可能想不到状压怎么打,不过我们可以拿部分分。因为打的顺序随便,于是我们就可以用全排列来枚举顺序,然后再暴力一个一个打就是的了。(注意精力为0不能打)
程序代码(暴力搜索50分)
#include
#include
#include
#include
#include
using namespace std;
int n,m,a,b,r[30],c[30],d[30],ans,sum,anss,summ,vis[30];
inline int read(){
int x=0,w=1;char ch;
while(ch!='-'&&(ch<'0'||ch>'9')) ch=getchar();
if(ch=='-') w=-1,ch=getchar();
while(ch>='0'&&ch<='9') x=(x<<3)+(x<<1)+(ch-48),ch=getchar();
return x*w;
}
inline void work(){//暴力打靶
ans=m;int aa=a;sum=0;
for(register int i=1;i<=n;++i) {
if(ans>0){
if(aa>d[r[i]]) {sum++;aa+=b;continue;}//如果能够一次打
else {//不能一次打
if(d[r[i]]%aa==0)ans=ans-((d[r[i]]/aa)+1)*c[r[i]];
else { ans=ans-(d[r[i]]/aa)*c[r[i]]; }
/*这里要分情况写,比如一个靶的耐久度为7,你每次打的伤害为2,
那你必须要花费c[i]*3的精力,而如果靶的耐久度为6,
则只需c[i]*2的精力*/
if(ans<=0) break;
sum++;aa+=b;
}
}
else break;
}
anss=max(anss,ans);
summ=max(summ,sum);
}
void dfs(int k) {//全排列
if(k==n+1) { work(); }
for(register int i=1;i<=n;++i) {
if(!vis[i]) { vis[i]=true; r[k]=i; dfs(k+1);vis[i]=false;}
}
}
int main(){
freopen("storm.in","r",stdin);
freopen("storm.out","w",stdout);
n=read(); m=read(); a=read(); b=read(); anss=0;
for(register int i=1;i<=n;++i) {c[i]=read();d[i]=read();}
dfs(1);
if(summ==n) cout<<"Yes"<else cout<<"No"<return 0;
}
/*
6 11030 5125 134
10698 11888
30903 2010
2668 23647
1604 27025
5281 21776
17729 10999
*/
程序代码(AC)
#include
#include
#include
#include
#include
using namespace std;
int n,m,a,b,ans2,ans1,d[30],c[30];
int s[2100000],f[2100000];
inline int read(){
int x=0,w=1;char ch;
while(ch!='-'&&(ch<'0'||ch>'9')) ch=getchar();
if(ch=='-') w=-1,ch=getchar();
while(ch>='0'&&ch<='9') x=(x<<3)+(x<<1)+(ch-48),ch=getchar();
return x*w;
}
int main(){
freopen("storm.in","r",stdin);
freopen("storm1.out","w",stdout);
n=read();m=read();a=read();b=read();
for(register int i=0;i//从0开始,方便状压
for(register int i=1;i<(1<>1]+(i&1);
//计算i这个数的二进制中有多少个1,一种写法,自己手动模拟一下即可
f[0]=m;
for(register int i=0;i<(1<1;++i)
for(register int j=0;jif((i&(1<0)//假如这一位还是0,那我们把它变为1
f[i|(1<1<0))*c[j]);
//后面那个==0就是像上面那个暴力程序中详解的那样去处理
for(register int i=(1<1;i;--i)
if(s[i]>ans1&&f[i]>0) ans1=s[i],ans2=f[i];
else if(s[i]==ans1&&f[i]>ans2) ans2=f[i];
if(ans1==n) puts("Yes"),cout<else puts("No"),cout<return 0;
}
本蒟认为这两到题都很好的将二进制运用到了状压里面,且两个都是状压搜索,以后会将状压DP补上.可以说先接触简单的,方便以后学习状压DP吧.