2016/12/10 Test Note


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
*/





  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值