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;
}