Problem ID:1000 18岁生日 HDU 1201
分析:需要注意的是什么时候+1天 1.出生在闰年且在3月前 2.18岁时是闰年在2月后 ,什么时候没有生日 如果生日是闰年2月29日 18岁无法过生日
代码:
#include<stdio.h>
#include<string.h>
bool Leap_year(int year){ // bool 布尔型判断闰年 bool类型只有两个值true & false
if((year%4==0 && year%100!=0)||(year%400==0)) return true;
else return false;
}
int main(){
int T,year,mon,day;
scanf("%d",&T);
while(T--){
int sum=0; // 统计天数
scanf("%d-%d-%d",&year,&mon,&day);
if( Leap_year(year) && mon==2 && day==29 ){ // 如果生日是闰年2月29日 18岁无法过生日
printf("-1\n"); continue;
}
// 需要注意的是什么时候+1天 1.出生在闰年且在3月前 2.18岁时是闰年在2月后
if( (Leap_year(year) && mon<3 ) || (Leap_year(year+18) && mon>=3 ))
sum++;
sum += 365;
int i;
for(i=year+1;i<year+18;i++){
sum += 365;
if(Leap_year(i)) sum = sum+1; // 闰年366
}
printf("%d\n",sum);
}
return 0;
}
Problem ID:1001 寻找素数对 HDU 1262
分析:先打素数表,输入中是一些偶整数M(5<M<=10000).所以数组开到10010,输出两个彼此最接近的素数 ,所以从中间开始向前寻找素数,如果 i 是素数且 m-i 也是素数输出并跳出循环
代码:
#include<cstdio>
#include<cstring>
#include<string>
#include<algorithm>
#include<cmath>
#include<queue>
#include<map>
#include<iostream>
using namespace std;
const int maxn = 10000+10;
int prime[maxn]={0};
void set_table(){
for(int i=2;i*i<maxn;i++){
if(prime[i]==0){
for(int j=2*i;j<maxn;j+=i)
prime[j]=1;
}
}
}
int main(){
int m;
set_table();
while(scanf("%d",&m)!=EOF ){
int t=m/2;
for(int i=t;i>=2;i--){
if(prime[i]==0 && prime[m-i]==0){
printf("%d %d\n",i,m-i);
break;
}
}
}
return 0;
}
Problem ID:1002 最小公倍数 HDU 1108
分析:辗转相除法模板,递归实现
int gcd(int a,int b){
return b==0?a:gcd(b,a%b);
}
代码:
#include<cstdio>
#include<cstring>
#include<string>
#include<algorithm>
#include<cmath>
#include<queue>
#include<map>
#include<iostream>
using namespace std;
int gcd(int a,int b){
return b==0?a:gcd(b,a%b);
}
int main(){
int a,b;
while(scanf("%d%d",&a,&b)!=EOF){
// sort(a,a+2,cmp);
printf("%d\n",a*b/gcd(a,b));
}
return 0;
}
Problem ID:1003 推箱子 HDU 1254
分析:需要判断人和箱子的相对位置,两个bfs嵌套,挪动一次箱子就判断一次人是否能到达使箱子挪动的地方。两次bfs,因为数据量不大,所以应该可以过
很棒的搜索题
需要注意的地方:
1.人不能穿过箱子,所以每次在处理人的行进路径时需要把地图G中箱子处转换成1
2.箱子不一定沿着到达目标点的最短路径前进
3.需要开4维数组记录人和箱子的相对状态state,因为人在箱子4个方向是不同的状态会产生不同的后继状态,因此需要标记
代码:
/*
Note:
一开始想把问题分解成两个子问题
1.用bfs找到最短路记录下路径 2.dfs判断人能否到达路径中每个点的前一个状态(即合法推箱子的状态)
后来发现有严重问题
例如:
1
7 6
4 1 1 1 1 1
0 1 0 0 0 1
0 1 0 1 0 1
0 2 0 1 0 3
0 0 0 1 0 1
0 0 0 0 0 1
0 0 0 0 0 1
我的思路只能选择两条最优路径中一条,然后进行判断,如果选择上面一条,那肯定是不对的,最合理的方法是选择下面的路径
所以这个思路是必错无疑
挪动一次箱子就判断一次人是否能到达使箱子挪动的地方
两次bfs,因为数据量不大,所以应该可以过
*/
#include<cstdio>
#include<cstring>
#include<queue>
using namespace std;
//#define test
int n,m;
int G[10][10];
int vis[10][10];
int state[9][9][9][9]; // 记录箱子和人的相对状态
int box_x,box_y,per_x,per_y,x_e,y_e; // box person X 的位置
const int dx[]={-1,1,0,0};
const int dy[]={0,0,-1,1};
struct point{
int x,y;
};
struct node{ // 存放现在的步数step 方向r box & per 的位置
int r,step;
struct point box;
struct point per;
};
bool check_per(int x,int y){ // 判断person的行走是否合法
if(x<0 || x>=n || y<0 || y>=m || vis[x][y] ) return false;
return true;
}
bool judge_per(int x_s,int y_s,int x_e,int y_e){ // person能否从(x_s,y_s)到达(x_e,y_e)
queue<point>q;
point cur,next;
for(int i=0;i<n;i++)
for(int j=0;j<m;j++)
vis[i][j]=G[i][j];
cur.x=x_s; cur.y=y_s;
vis[cur.x][cur.y]=1;
q.push(cur);
while(!q.empty()){
cur=q.front();
q.pop();
if(cur.x==x_e && cur.y==y_e) return true;
for(int i=0;i<4;i++){
next.x=cur.x+dx[i];
next.y=cur.y+dy[i];
if(check_per(next.x,next.y)){
vis[next.x][next.y]=1;
q.push(next);
}
}
}
return false;
}
bool check_box(int x,int y){
if(x<0 || x>=n || y<0 || y>=m || G[x][y]) return false;
return true;
}
int judge_box(){
queue<node> q;
node cur,next;
cur.box.x=box_x; cur.box.y=box_y;
cur.per.x=per_x; cur.per.y=per_y;
cur.step=0;
for(int i=0;i<4;i++) // 找到开始时人和箱子的相对方向r
if(cur.box.x-cur.per.x==dx[i] && cur.box.y-cur.per.y==dy[i]){
cur.r=i; break;
}
state[cur.per.x][cur.per.y][cur.box.x][cur.box.y]=1;
q.push(cur);
while(!q.empty()){
cur=q.front(); q.pop();
if(cur.box.x==x_e && cur.box.y==y_e) return cur.step;
for(int i=0;i<4;i++){
bool ok=false;
if(cur.r==i) ok=true; // 与人和箱子的相对方向相同时,开始推箱子
else{ // 换个方向尝试推箱子
G[cur.box.x][cur.box.y]=1;
ok=judge_per(cur.per.x,cur.per.y, cur.box.x-dx[i],cur.box.y-dy[i]);
G[cur.box.x][cur.box.y]=0;
}
if(ok){
next.box.x=cur.box.x+dx[i]; next.box.y=cur.box.y+dy[i];
if( check_box(next.box.x,next.box.y) ){ // 检查箱子的移动是否合法
next.per.x=cur.box.x; next.per.y=cur.box.y;
if(!state[next.per.x][next.per.y][next.box.x][next.box.y]){
state[next.per.x][next.per.y][next.box.x][next.box.y]=1;
next.r=i; // 记录下人和箱子的相对方向
next.step=cur.step+1;
q.push(next);
}
}
}
}
}
return -1;
}
int main(){
#ifdef test
freopen("Hdu 1254 推箱子 test case.txt","r",stdin);
#endif
int T;
int aim_x,aim_y;
scanf("%d",&T);
while(T--){
scanf("%d%d",&n,&m);
for(int i=0;i<n;i++)
for(int j=0;j<m;j++){
scanf("%d",&G[i][j]);
if(G[i][j]==2) {box_x=i;box_y=j; G[i][j]=0;}
else if(G[i][j]==3) {x_e=i ;y_e=j; G[i][j]=0;}
else if(G[i][j]==4) {per_x=i;per_y=j; G[i][j]=0;}
}
// 一开始时人就无法到达箱子的周围的某一个格子,这时就不需要搜索了,直接-1
bool ok=false;
for(int i=0;i<4;i++){ // 判断开始时是否在箱子周围
if(box_x-per_x==dx[i] && box_y-per_y==dy[i]) {
ok=true; break;
}
}
if(!ok){ // 判断能否到达箱子周围
G[box_x][box_y]=1; // 人无法穿过箱子**
for(int i=0;i<4;i++){
aim_x=box_x+dx[i]; aim_y=box_y+dy[i];
ok=judge_per(per_x,per_y,aim_x,aim_y);
if(ok){ per_x=aim_x; per_y=aim_y; break; } // 能到达箱子周围让person的位置更新一下即可
}
G[box_x][box_y]=0;
}
if(!ok) {printf("-1\n");continue;}
memset(state,0,sizeof(state));
printf("%d\n",judge_box());
}
return 0;
}
Problem ID:1004 唉,可爱的小朋友 HDU 2208
分析:一开始以为是匹配,GG,没认真读题......每个组至少有一个小球可以玩,而且每个组内不会有两个小朋友,相互不喜欢。如果A喜欢和B一起玩,则B也喜欢和A一起玩。因为数据很小 n,m,k<=10 应该直接暴力遍历一遍的。对于第x人来说,要么加入之前的小组,要么单立一个小组。因此需要遍历之前每个小组中的所有人,全部喜欢才能假如小组,否则就是单立小组。
代码:#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
//#define test
int n,m;
int rot[100],G[20][20]; // G[][]:二元关系 rot[]:rot[i]=j i的根是j
bool ok;
void dfs(int x,int y){ // 判断第x个人是否能够加入之前的集合中
if(ok) return;
if(x==n){ ok=true; return; }
if(y>m) return;
for(int i=0;i<x;i++){ // 遍历之前所有集合,找到集合的根
if(rot[i]!=i) continue;
int tag=1;
// 遍历此集合 如果没有不喜欢的人则加入集合
for(int j=i;j<x && tag;j++) // 因为在输入的时候把关系全部存放在了上三角形中,所以只需要遍历上三角形中的二元关系即可
if(rot[j]==i) tag=G[j][x];
if(tag){
rot[x]=i;
dfs(x+1,y);
rot[x]=x; // 将该点还原,以找到下一个该点的可能落脚点,以确保可以考虑到所有的可能
}
}
dfs(x+1,y+1); // 不能加入之前所有集合 -> y+1
}
int main(){
#ifdef test
freopen("Hdu 2208 唉,可爱的小朋友 test case.txt","r",stdin);
#endif
while(scanf("%d%d",&n,&m)!=EOF){
memset(G,0,sizeof(G));
ok=false;
for(int i=0;i<n;i++){
int k,t;
scanf("%d",&k);
rot[i]=i;
for(int j=0;j<k;j++){
scanf("%d",&t);
G[i][t]=1;
}
}
if(m>=n) printf("YES\n"); // 一开始球比人多直接yes
else{
dfs(0,0);
printf("%s",ok?"YES\n":"NO\n");
}
}
return 0;
}
Problem ID:1005 最少拦截系统 HDU 1257
分析:设置一个最大高度集合set_max[]如果下一个导弹比之前最大高度集合中某一个小,那就更新那个最大高度集合。如果扫描一遍后无法加入到之前的最大高度集,那么拦截系统数++
代码:#include<cstdio>
#include<cstring>
#include<string>
#include<algorithm>
#include<cmath>
#include<queue>
#include<map>
#include<iostream>
using namespace std;
const int maxn = 1000000;
int info[maxn];
int set_max[maxn];
int main(){
int n;
while(scanf("%d",&n)!=EOF){
int ans=1;
scanf("%d",&info[0]);
int k=0,j; // 标记最大集合
set_max[k++]=info[0];
for(int i=1;i<n;i++){
scanf("%d",&info[i]);
for(j=0;j<k;j++){
if(info[i]<set_max[j]){
set_max[j]=info[i];
break;
}
}
if(j==k){ // 找遍所有都没有,新加入set_max
set_max[k]=info[i];
k++;
}
}
/*
for(int i=0;i<k;i++)
printf("%d ",set_max[i]);
printf("\n");
*/
printf("%d\n",k);
}
return 0;
}
Problem ID:1006 连连看 HDU 1175
分析:
1.开始时就直接判断 如果起点处和目标点处数字不同,或则起点或终点有一个是0,直接no。
2.因为限定了最小转向次数,所以采用bfs单向搜,hdu 1728与之及其类似
/*
Note:
分析:
1.单方向BFS判断转折点,两次转折转折次数为3,从-1开始为2
2.一开始时就开始判断,如果起始点有一个是0或则起始点数字不同,则不需要受伤
*/
#include<cstdio>
#include<cstring>
#include<string>
#include<algorithm>
#include<cmath>
#include<queue>
#include<map>
#include<iostream>
using namespace std;
//#define test
const int maxn = 1000+2;
int G[maxn][maxn];
int n,m;
const int dx[]={-1,0,1,0}; // 上 右 下 左
const int dy[]={0,1,0,-1};
int vis[maxn][maxn];
bool ok;
struct point{
int x,y,cnt;
}s,e;
bool check(int x,int y){
return (x>=0 && x<n && y>=0 && y<m &&( G[x][y]==0 || ( x==e.x && y==e.y )))?true:false;
}
void bfs(){ //一个方向搜到底
queue<point> q;
s.cnt=-1;
q.push(s);
vis[s.x][s.y]=1;
int cnt;
while(!q.empty()){
point now = q.front(); q.pop();
for(int i=0;i<4;i++){
point t;
t.x=now.x+dx[i];
t.y=now.y+dy[i];
while( check(t.x,t.y) ){
if(!vis[t.x][t.y]){
vis[t.x][t.y]=1;
t.cnt=now.cnt+1;
q.push(t);
if(t.x==e.x && t.y==e.y && t.cnt<=2){ // 转折次数不超过两次相当于转3次
ok=true;
return ;
}
}
t.x=t.x+dx[i], t.y=t.y+dy[i]; // 继续一个方向搜
}
}
}
}
int main(){
#ifdef test
freopen("test.txt","r",stdin);
#endif
while(scanf("%d%d",&n,&m)!=EOF && n+m){
memset(G,0,sizeof(G));
for(int i=0;i<n;i++)
for(int j=0;j<m;j++)
scanf("%d",&G[i][j]);
int q;
scanf("%d",&q);
for(int i=0;i<q;i++){
ok=false;
memset(vis,0,sizeof(vis));
scanf("%d%d%d%d",&s.x,&s.y,&e.x,&e.y);
s.x-- , s.y-- , e.x-- , e.y--;
if((G[s.x][s.y]!=G[e.x][e.y]) || G[s.x][s.y]==0 || G[e.x][e.y]==0){
printf("NO\n");
continue;
}
bfs();
if(ok)
printf("YES\n");
else
printf("NO\n");
}
}
return 0;
}
Problem ID:1007 画8 HDU 1256
分析:模拟,读题读题读题读题,认真认真认真认真。计算出上下圈高度宽度 s_h , x_h , L ,需要注意输出时后面不能有多余空格,否则会PE
代码:
#include<cstdio>
#include<cstring>
#include<string>
#include<algorithm>
#include<cmath>
#include<queue>
#include<map>
#include<iostream>
using namespace std;
//#define test
char G[1000][1000];
int main(){
int n,h,kase=0;
char str;
#ifdef test
freopen("test.txt","r",stdin);
freopen("output.txt","w",stdout);
#endif
cin>>n;
while(n--){
if(kase!=0) printf("\n");
kase++;
cin>>str >> h;
int L = h/6+1; // 宽度
int s_h=(h-3)/2;
int x_h=(h-3)%2==0?(h-3)/2:(h-3)/2+1;
memset(G,' ',sizeof(G));
for(int j=0;j<2*L+x_h;j++)
if(j>=L && j<L+x_h) G[0][j]=G[s_h+1][j]=G[h-1][j]=str;
for(int i=0;i<h;i++){
if(i==0 || i==s_h+1 || i==h-1) continue;
for(int j=0;j<2*L+x_h;j++)
if(j>=L && j<L+x_h) continue;
else G[i][j]=str;
}
for(int i=0;i<h;i++){
if(i==0 || i==s_h+1 || i==h-1){
for(int j=0;j<L+x_h;j++)
printf("%c",G[i][j]);
printf("\n");
}
else{
for(int j=0;j<2*L+x_h;j++)
printf("%c",G[i][j]);
printf("\n");
}
}
}
return 0;
}
Problem ID:1008 The calculation of GPA HDU 1202
分析:成绩是实型,需要注意的是89.5这样的成绩,多组测试数据多组测试数据多组测试数据多组测试数据!!!%$#@
代码:#include<cstdio>
#include<cstring>
#include<string>
#include<algorithm>
#include<cmath>
#include<queue>
#include<map>
#include<iostream>
using namespace std;
//#define test
const int maxn = 10000;
int main(){
int n;
#ifdef test
freopen("test.txt","r",stdin);
#endif
while(scanf("%d",&n)!=EOF){
double sum,m;
sum=m=0;
int flag=0;
for(int i=0;i<n;i++){
double s,p;
cin>>s>>p;
if(p==-1){
flag++;
continue;
}
m+=s;
if(p>=90) p=4;
else if((p>=80)&&(p<90)) p=3;
else if((p>=70)&&(p<80)) p=2;
else if((p>=60)&&(p<70)) p=1;
else p=0;
sum += p*s;
}
if(sum==0 || flag==n) printf("-1\n");
else printf("%.2lf\n",sum/m);
}
return 0;
}
Problem ID:1000 悼念512汶川大地震遇难同胞——老人是真饿了 HDU 2187
分析:最简单的思路,先挑最便宜的买,能买光就买光,能买多少就买多少
代码:#include<cstdio>
#include<cstring>
#include<string>
#include<algorithm>
#include<cmath>
#include<queue>
#include<map>
#include<iostream>
using namespace std;
struct Node{
int p,h;
}info[1000+10];
bool cmp(Node a,Node b){
if(a.p<b.p) return true;
else return false;
}
int main(){
int n,m,c;
scanf("%d",&c);
while(c--){
double ans=0;
scanf("%d%d",&n,&m); // n是钱数
for(int i=0;i<m;i++)
scanf("%d%d",&info[i].p,&info[i].h);
sort(info,info+m,cmp);
for(int i=0;i<m;i++){
if(n-info[i].p*info[i].h>=0){
ans += info[i].h;
n -= info[i].p*info[i].h;
}
else{
ans += n*1.0/info[i].p;
n=0;
}
}
printf("%.2lf\n",ans);
}
return 0;
}
/*
2
10 2
3 3
4 4
7 2
3 3
4 4
*/