问题 A: 0-1背包问题(基于暴力)
题目描述
给定一个容积为m的背包,去尝试装n个重量为wi、价值为vi的物体,求能装下的物体的最大价值。
输入
输入的第一行有两个整数n和m,分别表示物品的个数,背包的最大容量。
接下来n行,每行两个数字,每个物品的重量w和价值v
数据保证1<=n<=20,1<=w , v<=2000
输出
一个整数,表示可获得的最大价值。
样例输入
3 30
16 45
15 25
15 25
样例输出
50
思想:裸的01背包
#include<bits/stdc++.h>
using namespace std;
const int maxn=40005;
int dp[maxn];
int main()
{
int n,m;
scanf("%d%d",&n,&m);
for(int i=0;i<n;i++)
{
int w,v;
scanf("%d%d",&w,&v);
for(int j=m;j>=w;j--)
dp[j]=max(dp[j],dp[j-w]+v);
}
int ans=0;
for(int i=0;i<=m;i++)
ans=max(ans,dp[i]);
printf("%d\n",ans);
return 0;
}
问题 B: 八皇后问题(基于暴力)
题目描述
皇后问题。所谓的n皇后问题,是指在n×n的棋盘上放置彼此不受攻击的n个皇后,按照国际象棋的规则,皇后可以攻击与之处在同一行或同一列或同一斜线上的棋子。后问题等价于在n×n格的棋盘上放置n个皇后,任何2个皇后不放在同一行或同一列或同一斜线上。
为了使问题更加有趣,我们需要求在n×n的棋盘上,放置k个皇后,共有多少种可能的方案数?
输入
两个正整数n和k,(n,k<=10)
输出
一个整数,表示方案数。
样例输入
8 8
样例输出
92
思想:n*n的棋盘放k个皇后,dfs暴力加剪枝。当然可以本地打表,输出表。
#include<bits/stdc++.h>
using namespace std;
int sum,n,k;
int Map[15];
int check(int x)
{
for(int i=1;i<x;i++)
if((abs(x-i)==abs(Map[x]-Map[i])) || (Map[x]==Map[i]))
return 0;
return 1;
}
void dfs(int id,int flag)
{
if(id>n)
{
if(flag==0)
sum++;
return ;
}
else if(n-id+1 < flag)
return ;
for(int i=1;i<=n;i++)
{
Map[id]=i;
if(check(id))
dfs(id+1,flag-1);
}
Map[id]=-1000;
dfs(id+1,flag);
}
int main()
{
scanf("%d%d",&n,&k);
sum=0;
if(n>=k)
dfs(1,k);
printf("%d\n",sum);
return 0;
}
问题 C: 李白饮酒--蓝桥杯原题改编(基于暴力)
题目描述
话说大诗人李白,一生好饮。幸好他从不开车。一天,他提着酒壶,从家里出来,酒壶中有酒2斗。他边走边唱:
无事街上走,提壶去打酒。逢店加一倍,遇花喝一斗。
这一路上,他一共遇到店5次,遇到花10次,已知最后一次遇到的是花,他正好把酒喝光了。请你计算李白遇到店和花的次序,可以把遇店记为a,遇花记为b。则babaabbabbabbbb 就是合理的次序。像这样的答案一共有多少呢?请你计算出所有可能方案的个数。
为了使问题更加有趣,我们假设他遇到店s次,花f次,你的任务是计算此时的方案总数。
输入
两个整数s和f,分别表示李白遇到的店和花的次数。(s+f<=20)
输出
一个整数,表示方案总数。
样例输入
5 10
样例输出
14
思想:2进制枚举,最多2^10
#include<bits/stdc++.h>
using namespace std;
int ans,s,f;
void dfs(int dian,int hua,int jiu,int flag)
{
if(dian==s && hua==f && jiu==0 && flag==1)
{
ans++;
return ;
}
if(dian<s)
dfs(dian+1,hua,jiu*2,0);
if(hua<f)
dfs(dian,hua+1,jiu-1,1);
}
int main()
{
scanf("%d%d",&s,&f);
if(f==0)
{
printf("0\n");
return 0;
}
ans=0;
dfs(0,0,2,0);
printf("%d\n",ans);
return 0;
}
问题 D: 组素数
题目描述
素数就是不能再进行等分的数。比如:2、3、5、7、11 等。9 = 3 * 3 说明它可以3等分,因而不是素数。
我们国家在1949年建国。如果只给你 1、9、4和9 这4个数字卡片,可以随意摆放它们的先后顺序,那么,你能组成多少个4位的素数呢?
比如:1949,4919 都符合要求。
为了使问题更加有趣,我们输入n个数字,求这n个数字可以组成的数字中的素数。
输入
第一行一个整数n。(n<=6)
第二行n个空格分隔的整数,仅包含1~9
输出
输出所有符合的素数。若没有可行解,则输出-1。
样例输入
4
1 9 4 9
样例输出
1499
1949
4919
9419
9491
9941
思想:1e6素数打表,然后全排列一下判断素数就行了。
#include<bits/stdc++.h>
using namespace std;
const int maxn=1e6+5;
int a[10];
int vis[maxn];
void init()
{
for(int i=4;i<maxn;i+=2)
vis[i]=1;
for(int i=3;i<maxn;i++)
{
if(vis[i]==0)
{
for(int j=i+i;j<maxn;j+=i)
vis[j]=1;
}
}
}
int main()
{
init();
int n;
scanf("%d",&n);
for(int i=0;i<n;i++)
scanf("%d",&a[i]);
sort(a,a+n);
int flag=0;
int ans=0;
do{
int Ans=0;
for(int i=0;i<n;i++)
Ans=Ans*10+a[i];
if(vis[Ans]==0)
{
flag=1;
printf("%d\n",Ans);
}
}while(next_permutation(a,a+n));
if(flag==0)
printf("-1\n");
return 0;
}
问题 E: 匪警110问题
题目描述
匪警请拨110,即使手机欠费也可拨通!为了保障社会秩序,保护人民群众生命财产安全,警察叔叔需要与罪犯斗智斗勇,因而需要经常性地进行体力训练和智力训练!
某批警察叔叔正在进行智力训练:
12 3 4 5 6 7 8 9 = 110
请看上边的算式,为了使等式成立,需要在数字间填入加号或者减号(可以不填,但不能填入其它符号)。之间没有填入符号的数字组合成一个数,例如:12+34+56+7-8+9 就是一种合格的填法;123+4+5+67-89 是另一个可能的答案。
请你利用计算机的优势,帮助警察叔叔快速找到所有答案。形如:
12+34+56+7-8+9
123+4+5+67-89
....
为了使问题更加有趣,我们把后面的数字110换成n。注意:这里只要求你计算方案数。不必输出每种方案。
输入
一个整数n,如题所述。(-2000000000<=n<=2000000000)
输出
一个整数,表示方案数。
样例输入
110
样例输出
10
思想:三进制枚举下,考虑当前放什么。3^8
#include<bits/stdc++.h>
using namespace std;
int main()
{
int a[10]={1,2,3,4,5,6,7,8,9};
int ans=0;
int n;
scanf("%d",&n);
int m=(int)pow(3,8);
for(int i=0;i<m;i++)
{
int TT=1,sum=0;
int temp=i;
int op=1;
for(int j=1;j<9;j++)
{
if(temp%3==0)
TT=TT*10+a[j];
else if(temp%3==1)
{
if(op==1)
{
sum+=TT;
TT=a[j];
}
else
{
sum-=TT;
TT=a[j];
}
op=1;
}
else
{
if(op==1)
{
sum+=TT;
TT=a[j];
}
else
{
sum-=TT;
TT=a[j];
}
op=2;
}
temp/=3;
}
if(op==1)
sum+=TT;
else
sum-=TT;
if(sum==n)
ans++;
}
printf("%d\n",ans);
return 0;
}
问题 F: 敢死队
题目描述
G将军有一支训练有素的军队,这个军队除了G将军外,每名士兵都有一个直接上级(可能是其他士兵,也可能是G将军)。现在G将军将接受一个特别的任务,需要派遣一部分士兵(至少一个)组成一个敢死队,为了增加敢死队队员的独立性,要求如果一名士兵在敢死队中,他的直接上级不能在敢死队中。请问,G将军有多少种派出敢死队的方法。注意,G将军也可以作为一个士兵进入敢死队。
输入
输入的第一行包含一个整数n(1<=n<=1000),表示包括G将军在内的军队的人数。军队的士兵从1至n编号,G将军编号为1。接下来n-1个数,分别表示编号为2, 3, ..., n的士兵的直接上级编号,编号i的士兵的直接上级的编号小于i。
输出
一个整数,表示方法数。注意:答案可能会很大,可能不足以64位整数存储,因此你需要输出模除1000000007后的结果。
样例输入
4
1 2 3
样例输出
7
思想:树形DP,考虑子孩子对于父亲节点的影响,如果当前不去,那么他的子孩子都可以,如果当前去,他的子孩子都不能去。
#include<bits/stdc++.h>
using namespace std;
const int maxn=1005;
typedef long long ll;
const ll mod = 1e9+7;
ll dp[maxn][2];
vector<int>V[maxn];
int main()
{
int n;
scanf("%d",&n);
for(int i=2;i<=n;i++)
{
int fa;
scanf("%d",&fa);
V[fa].push_back(i);
}
for(int i=n;i>=1;i--)
{
dp[i][0]=dp[i][1]=1ll;
for(int j=0;j<V[i].size();j++)
{
//printf("~%lld %lld\n",dp[V[i][j]][0],dp[V[i][j]][1]);
dp[i][0]=(dp[i][0]%mod*(dp[V[i][j]][0]+dp[V[i][j]][1])%mod)%mod;
dp[i][1]=(dp[i][1]%mod*dp[V[i][j]][0]%mod)%mod;
//printf("%lld %lld\n",dp[i][0],dp[i][1]);
}
}
printf("%lld\n",(dp[1][0]+dp[1][1]-1ll)%mod);
return 0;
}
问题 G: 独立任务最优调度问题
题目描述
用两台处理机A和B处理n个作业。设第i个作业交给A处理需要时间ai,交给B处理需要时间bi。由于各作业的特点和机器的性能关系,ai和bi之间没有明确的大小关系。既不有将一个作业分开由2台机器处理,也没有一台机器能同时处理2个作业。设计一个算法,使得这两台机器处理完这n个作业的时间最短。
输入
第一行一个整数n,表示任务数(1<=n<=20)。
第二行n个整数,分别表示第i个任务在机器A上的处理时间。
第三行n个整数,分别表示第i个任务在机器B上的处理时间。
处理时间数据范围(1~40)
输出
一个整数,表示最少的完成这些任务的时间 。
样例输入
3
1 4 7
2 5 8
样例输出
7
思想:直接2进制枚举情况取一个最小的即可。2^20 。
或者可以考虑下DP dp[i][j]表示第i个任务,A机器花费了j时间。dp[i][j]=min(dp[i-1][j]+b[i],dp[i-1][j-a[i])
枚举:
#include<bits/stdc++.h>
using namespace std;
int a[25];
int b[25];
int main()
{
int n;
scanf("%d",&n);
for(int i=0;i<n;i++)
scanf("%d",&a[i]);
for(int i=0;i<n;i++)
scanf("%d",&b[i]);
int m=(int)pow(2,n);
int ans=1<<30;
for(int i=0;i<=m;i++)
{
int temp=i;
int sum1=0;
int sum2=0;
for(int j=0;j<n;j++)
{
if(temp%2==0)
sum1+=a[j];
else
sum2+=b[j];
temp=temp/2;
}
temp=max(sum1,sum2);
ans=min(ans,temp);
}
printf("%d\n",ans);
return 0;
}
DP
#include<bits/stdc++.h>
using namespace std;
int a[25];
int b[25];
int dp[25][1000];
int main()
{
int n,sum=0;
scanf("%d",&n);
for(int i=0;i<n;i++)
{
scanf("%d",&a[i]);
sum+=a[i];
}
for(int i=0;i<n;i++)
scanf("%d",&b[i]);
for(int i=1;i<=n;i++)
{
for(int j=0;j<=sum;j++)
{
if(j<a[i-1])//A不够做这个任务
dp[i][j] = dp[i-1][j]+b[i-1];
else if(dp[i-1][j]+b[i-1]<dp[i-1][j-a[i-1]])
dp[i][j] = dp[i-1][j]+b[i-1];
else
dp[i][j] = dp[i-1][j-a[i-1]];
}
}
int Max=1<<30;
for(int i=0;i<=sum;i++)
Max=min(Max,(max(dp[n][i],i)));
printf("%d\n",Max);
return 0;
}