共17道题目,其中最后五题是拓展题,数位dp和插头dp没有写出来
按照过题的顺序记录, 可以从下往上看~
E-Coins
题意: 告诉你 n 种钱币的面值和数目,求【1,m】之间,有多少数目是用这些钱币能恰好凑出的?
思路:经典裸题,参考《挑战程序设计》P74
注意: 内存限制,可以参考书上的利用奇偶性减少内存消耗
B-免费馅饼
题意: 现在给这条小径如图标上坐标:
————————————
0 1 2 3 4 5 6 7 8 9 10
假设馅饼都掉落在0-10这11个位置。gameboy每秒种只有在移动不超过一米的范围内接住坠落的馅饼。开始时gameboy站在5这个位置,因此在第一秒,他只能接到4,5,6这三个位置中其中一个位置上的馅饼。问gameboy最多可能接到多少个馅饼?(假设他的背包可以容纳无穷多个馅饼)
思路: 定义以时间为序,决策有 站着不动 ,左移和右移两种,开一个数组记录在t时刻,i点处掉落的馅饼数
J-Humble Numbers
题意: 只由2,3,5,7相乘得到的数字为Humble Numbers,如1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 12, 14, 15, 16, 18, 20, 21, 24, 25, 27, …
求第n个Humber Numbers
思路: 参考紫皮 第十章
注意: G++和C++ 编译上的不同
D-How to type
思路: 定义状态d[i][0]和d[i][1]分别表示第i个字符大写和小写所需的最小操作数,递推一下
A- Big event in HDU ****
思路: 要转换一下思路,转换成求0-sum 值中用有n人的m个学院最多凑出多少个数,然后找出这些数中最靠近sum/2的数即可
code:http://paste.ubuntu.com/25197810/
L-How many ways
题意: 这是一个简单的生存游戏,你控制一个机器人从一个棋盘的起始点(1,1)走到棋盘的终点(n,m)。游戏的规则描述如下:
1.机器人一开始在棋盘的起始点并有起始点所标有的能量。
2.机器人只能向右或者向下走,并且每走一步消耗一单位能量。
3.机器人不能在原地停留。
4.当机器人选择了一条可行路径后,当他走到这条路径的终点时,他将只有终点所标记的能量。
我们的问题是机器人有多少种方式从起点走到终点。这可能是一个很大的数,输出的结果对10000取模。
code:http://paste.ubuntu.com/25197837/
Beans ****
题意
注意:
分别开一个行和列的数组,注意最优解可以隔一行,或者隔两行取
code:http://paste.ubuntu.com/25197890/
Doint homework again
思路: 转换一下思路,求怎样安排获得的分最大,最后减一下最大值就可以了,应该也算01背包?
code: http://paste.ubuntu.com/25197962/
树形dp ****
题意 公司里上级和下级形成一棵树,每个人期待参加派对的程度都不同,求在直接上级和下级不同时出现在派对的情况下,最大的期待总值
思路: 先是怎么储存树,我用的vector
然后分别用0,1存储这个人不参加和参加派对时的最大期待值
code: http://paste.ubuntu.com/25198008/
G&H 求最大相同字符的子矩阵面积 *****
思路: 本来是很不会矩阵求面积的…… 后来居然看着看着 看通畅了……
记录每一列的最大深度,求出到最左和最右的距离,用这个面积来更新ans
code: http://paste.ubuntu.com/25198040/
因为最后两题想直接给出代码,所以把两题没有做出来的放到上面来
数位dp
题意: 求一个区间内满足条件的数有多少个,条件是该数可以写成k个b的不同次方的和
参考: 刘聪 《浅谈数位类统计问题》
插头dp HDU P1693
题意:
呃…… 略略略
状压dp *********
思路: 先看数据范围 1 ≤ M ≤ 12; 1 ≤ N ≤ 12 可以状压没有错
然后枚举,d[i][j] 为第i行为j排列时 最大的排列数
#include <iostream>
#include <cstdio>
#include <cstring>
#include <string>
#include <cmath>
#include <algorithm>
using namespace std;
typedef long long LL;
int pic[15][15];
const int bit=(1<<14)-1;
LL d[15][bit+10];
int n,m;
const int mod=1e8;
bool able(int i,int j){ //判断第i行 j种排列可行,1.没有两个1相邻,2.没有荒地种了1
int lim=0;
for(int k=0;k<m;k++)
lim=(lim<<1)+pic[i][k];
if(lim&j) return false;
int be=j&1;j>>=1;
while(j){
if(be==1&&(j&1)) return false;
be=j&1; j>>=1;
}
return true;
}
bool judge(int i,int j){ //判断相邻两行的i,j排列是否可行,相邻字符不都为1则可行
bool res=true;
for(int k=0;k<m;k++){
int n=i&1,m=j&1;
if(n==1&&m==1) res=false;
i>>=1,j>>=1;
}
return res;
}
void print(int j){ //输出解
while(j){
printf("%d",j&1);
j>>=1;
}
cout<<endl;
}
int main()
{
//freopen("1.txt","r",stdin);
while(~scanf("%d%d",&n,&m)){
memset(pic,0,sizeof(pic));
memset(d,0,sizeof(d));
for(int i=0;i<n;i++)
for(int j=0;j<m;j++){
int t;
scanf("%d",&t);
pic[i][j]=!t;
}
for(int i=0;i<(1<<m);i++)
if(able(0,i)) d[0][i]=1;
for(int i=1;i<n;i++){
for(int j=0;j<(1<<m);j++){
if(!able(i,j)) {d[i][j]=0;continue;} //第i行可以取j排列
for(int k=0;k<(1<<m);k++){
if(judge(j,k)&&able(i-1,k)) d[i][j]=(d[i][j]+d[i-1][k])%mod; //i-1行可以取k排列,i行以取j排列时 可以取的排列数
}
}
}
LL ans=0;
for(int j=0;j<(1<<m);j++) ans=(ans+d[n-1][j])%mod;
printf("%lld\n",ans%mod);
}
return 0;
}
区间dp **********
思路: 给出一个多边形,已知每一个顶点的坐标,告诉你每一刀的消耗与坐标的关系式 costi, j = |xi + xj| * |yi + yj| % p 。求将这个多边形分为n-2个三角形所需要的最小消耗
#include <iostream>
#include <cstdio>
#include <cstring>
#include <string>
#include <cmath>
#include <algorithm>
#include <vector>
using namespace std;
struct Point{ //定义点的结构体
int x,y;
Point(int x=0,int y=0):x(x),y(y) {};
};
bool operator < (const Point& a,const Point& b){ //两种排序
return (a.x!=b.x) ? a.x<b.x: a.y>b.y;
}
bool cmp (const Point &a,const Point &b){
return (a.x!=b.x) ? a.x>b.x:a.y<b.y;
}
vector<Point> vec; //点的向量集
const int INF=1e9;
int n,q;
int d[310][310];
int c[310][310];
//已知三角形三个顶点的坐标,求面积,利用公式
double area(int i,int j,int k){
Point a=vec[i],b=vec[j],c=vec[k];
return (fabs(a.x*(b.y-c.y)+b.x*(c.y-a.y)+c.x*(a.y-b.y))/2.0);
}
//判断点是不是在已有的多边形的内部,如果是则为凹多变形,理解
bool judge(int i,int j,int k){
for(int t=0;t<n;t++){
if(t==i||t==j||t==k) continue;
if(area(i,j,k)==area(i,j,t)+area(i,k,t)+area(j,k,t)) return false;
}
return true;
}
// 用动态规划求最优解,重点d[i][j]=min(d[i][j],d[i][k]+d[k][j]+c[i][k]+c[k][j]);
bool solve(){
for(int i=0;i<n;i++)
for(int j=i+1;j<n;j++){
if(i-j==1||j-i==1) c[i][j]=c[j][i]=0;
else {
c[i][j]=c[j][i]=(abs(vec[i].x+vec[j].x)*abs(vec[i].y+vec[j].y))%q;
}
}
for(int i=n-2;i>=0;i--)
for(int j=i+1;j<n;j++){
if(j==i+1) d[i][j]=0;
else{
d[i][j]=INF;
for(int k=i+1;k<j;k++){
if(!judge(i,j,k)) return false; //判断凸边形
d[i][j]=min(d[i][j],d[i][k]+d[k][j]+c[i][k]+c[k][j]);
}
}
}
return true;
}
//给点排序,使点按逆时针方向形成一个多边形
void Sort(){
sort(vec.begin(),vec.end());
int lx,ly,rx,ry;
lx=vec[0].x,ly=vec[0].y;
rx=vec[n-1].x,ry=vec[n-1].y;
double k=double (ly-ry)/double (lx-rx);
double b=double(ly)-k*lx;
vector<Point> vec2;
vec2.clear();
for(int i=0;i<n;i++)
{
if(vec[i].x*k-vec[i].y+b<=0){
vec2.push_back(vec[i]);
vec[i].x=vec[i].y=-INF;
}
}
sort(vec.begin(),vec.end(),cmp);
for(int i=0;i<n;i++)
if(vec[i].x>=lx) vec2.push_back(vec[i]);
swap(vec,vec2);
}
int main()
{
//freopen("1.txt","r",stdin);
while(~scanf("%d%d",&n,&q)){
vec.clear();
for(int i=0;i<n;i++){
int x,y; scanf("%d%d",&x,&y); //读取每个点
vec.push_back(Point(x,y));
}
Sort();
memset(d,-1,sizeof(d));
bool jud=solve();
if(!jud){
printf("I can't cut.\n"); continue;
}
printf("%d\n",d[0][n-1]);
}
return 0;
}