Exercises 1

Communication System // oj 1018

这道题如果纯暴力容易超时。考虑到在一定的bandwidth下,price越小越好,进行优化。

第一步改进是用multimap储存,对于每一层中的每一个设备,只要找不同层里bandwidth比它大的中 最小的price。这样已经可以过了,但800+ms

第二步改进,用map储存,在输入时,每层只保留bandwidth相同的里面price最小的。这样是700-800ms

第三步改进,不要再去搜“每一层中的每一个设备”。考虑到,我们想让最小的B尽量大,我们在输入时找到最大B最小的那一层,只遍历这一层的每一个设备即可。这样是10-20ms,在数据结构和排序上还可以再优化,比如找到b比它大的最小price。

问题在于,这道题卡了很久,原因有二:

①搜索的框架不是很清晰。上述第三步改进,最初自己搞成了用各层中bandwidth最大的那个设备与其他层遍历,这样有遗漏,因为对于非“最小之最大”所在层,如果层里有一些price很小的、bandwidth非最大的,这些会被遗漏。实际上,选取一层,对该层所有设备与其他层进行遍历,则减小了遗漏的可能,为了彻底杜绝遗漏,我们选取最大bandwidth是所有层中最小的那一层,即“最小之最大”所在层。

②多组数据下的初始化,这里包括了ans 和 m,编程习惯还是不太好呀……

#include<iostream>
#include<cstring>
#include<map>
#include<algorithm>
using namespace std;
int n;
typedef map<int,int>::iterator IT;
double ans;
int main(){
	int t;
	scanf("%d",&t);
	while(t--){
		scanf("%d",&n);
		ans=0;
		map<int,int> m[102];
		int minRow,minB=(1<<30);
		for(int i=0;i<n;++i){
			int tt,b,p;
			scanf("%d",&tt);
			while(tt--){
				scanf("%d%d",&b,&p);
				IT it=m[i].find(b);
				if(it==m[i].end()) m[i].insert(make_pair(b,p));
				else if(it->second>p){
					m[i].erase(it);
					m[i].insert(make_pair(b,p));
				}
			}
			if((--m[i].end())->first<minB){
				minB=(--m[i].end())->first;
				minRow=i;
			}
		}
		IT t=m[minRow].begin();
		for(;t!=m[minRow].end();++t){
			int P=t->second;
			bool f=1;
			for(int j=0;j<n;++j){
				if(j==minRow) continue;
				IT tt=m[j].lower_bound(t->first);
				if(tt!=m[j].end()) {
					int minP=(1<<30);
					for(;tt!=m[j].end();++tt) minP=min(minP,tt->second);
					P+=minP;
				}
				else{
					f=0;break;
				} 	
			}
			if(f) ans=max(ans,(double)t->first/P);
		}
		printf("%.3lf\n",ans);
	}
}

附上自己搞的测试数据

3
4 100 25 100 25 150 35 80 25
3 120 80 155 40 120 100
3 100 110 100 100 100 100 【0.606】
3
2 150 1 180 35
3 120 100 80 80 60 10
3 100 110 80 90 150 70 【0.741】

选择客栈 // oj 4034

与其说是动规,不如说是递推。

这些数学方面的东西练习得太少。所以,这是个潜在隐患。

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
//初始思路是搜索,但数据量是200000,那怎么办?数学 
//前i家店方案总数,其实只要找到 i 之前的第一个价格合适的即可(不考虑颜色) 
int n,k,p;
struct hotel{
	int color;
	int pay;
}h[200002]; 
int dp[200002]={0}; //前i家店方案总数 
int a[200002]={0};//前i-1中与i同色调的个数 
int b[200002]={0};//前i-1中与i同色调的最大号
int ans[200002]={0}; //第i家店的方案数 

int main(){
	scanf("%d%d%d",&n,&k,&p);
	for(int i=1;i<=n;++i) {
		scanf("%d%d",&h[i].color,&h[i].pay);
		for(int j=i-1;j>0;--j){
			if(h[j].color==h[i].color){
				b[i]=j;
				a[i]=a[j]+1;
				break;
			}
		}
	}
	for(int i=2;i<=n;++i){
		int k; //前i中价格合适的最大号 
		for(k=i;k>0;--k) if(h[k].pay<=p) break; 
		if(k>=b[i]) ans[i]=a[i];
		else ans[i]=ans[b[i]]; //价格合适的最大号小于同色最大号 
		dp[i]=ans[i]+dp[i-1];
	}
	printf("%d",dp[n]);
}

恼人的青蛙  // oj 1054 2812

这道题本来可以没那么困难的,然而长时间没写程序,一些debug的感觉丢了不少

这道题的易错点在于,寻找路径时,如果下一个点找不到,说明这条路径就根本不通,因为如果通的话,按部就班找下去,一定能找到靠近边缘的最后一个点。

#include <iostream>
#include <algorithm>
using namespace std;
struct loc{
	int x,y;
	loc(){}
	loc(int x_,int y_):x(x_),y(y_){}
	
} tread[5002];
bool operator<(const loc&a,const loc&b){
	if(a.x==b.x) return a.y<b.y;
	return a.x<b.x;
}
int R,C,N;
int maxStep,cntStep;

int main(){
	scanf("%d%d%d",&R,&C,&N);
	for(int i=0;i<N;++i) scanf("%d%d",&tread[i].x,&tread[i].y);	
	sort(tread,tread+N);
	maxStep=2;
	for(int i=0;i<N-2;++i){
		for(int j=i+1;j<N-1;++j){
			int dx=tread[j].x-tread[i].x;
			int dy=tread[j].y-tread[i].y;
			int px=tread[i].x-dx, py=tread[i].y-dy;
			if(px>0&&px<=R&&py>0&&py<C) continue; //确保这是起始点
			px=tread[i].x+(maxStep-1)*dx;
			py=tread[i].y+(maxStep-1)*dy;
			if(px>R||px<1) break;
			if(py>C||py<1) continue; //y越界,换下一个j 
			cntStep=2;
			int x=tread[j].x+dx, y=tread[j].y+dy;
			while(x>0&&y>0&&x<=R&&y<=C){ 
				if(!binary_search(tread,tread+N,loc(x,y))){
					cntStep=0; //坑死我了…… 
					break;
				}
				x+=dx;
				y+=dy;
				++cntStep;
			}
			if(cntStep>maxStep) maxStep=cntStep;
		}
	}
	if(maxStep<=2) maxStep=0;
	printf("%d\n",maxStep);		
	return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值