[CodeForces] 830A Office Keys
传送门
codeforces
luogu
题目描述
There are n people and k keys on a straight line. Every person wants to get to the office which is located on the line as well. To do that, he needs to reach some point with a key, take the key and then go to the office. Once a key is taken by somebody, it couldn't be taken by anybody else.
You are to determine the minimum time needed for all n people to get to the office with keys. Assume that people move a unit distance per 1 second. If two people reach a key at the same time, only one of them can take the key. A person can pass through a point with a key without taking it.
思路
首先读入后,按照位置分别排序,然后处理一个dis数组,表示第i个人拿了第j把钥匙后去办公室的路程。 然后就是一个01背包,最开始的时候人是瓷的,写了三重循环,一直TLE,附上磁珠代码233333
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<math.h>
using namespace std;
int n,k,p;
int man[1005];
int key[2005];
int dis[1005][2005];
int dp[1005][2005];
inline int cmp(int a,int b){
return a<b;
}
int minn(int a,int b){
if(a>=b)return b;
return a;
}
int maxx(int a,int b){
if(a>=b)return a;
return b;
}
int main(){
//freopen("1.in","r",stdin);
cin>>n>>k>>p;
for(register int i=1;i<=n;i++){
cin>>man[i];
}
for(register int i=1;i<=k;i++){
cin>>key[i];
}
sort(man+1,man+n+1,cmp);
sort(key+1,key+k+1,cmp);
for(register int i=1;i<=n;i++){
for(register int j=1;j<=k;j++){
dis[i][j]=fabs(man[i]-key[j])+fabs(key[j]-p);
dp[i][j]=999999999;
}
}
dp[0][0]=0;
//cout<<"fuck"<<endl;
for(register int i=1;i<=n;i++){ //1-ige re
for(register int j=i;j<=k;j++){ //1-j zhongxuanze
int xx=minn(j,n);
for(register int kk=i;kk<=xx;kk++){
if(kk<1)continue;
dp[i][j]=minn(dp[i][j],maxx(dp[i-1][kk-1],dis[kk][j]));
// cout<<i<<' '<<j<<' '<<kk<<endl;
// cout<<dp[i][j]<<' '<<dp[i-1][kk]<<' '<<dis[kk][j]<<endl<<endl;
}
}
}
// while(1){
// int x,y;
// cin>>x>>y;
// cout<<dp[x][y]<<endl;
// }
int ans=999999999;
for(register int i=n;i<=k;i++){
ans=min(ans,dp[n][i]);
}
cout<<ans<<endl;
}
当时用kk来表示i-1个人一共拿到第kk把钥匙是的最大步数的最小值,就是因为枚举这个kk然后挂了,后来发现不需要枚举kk,因为dp[i][j]只能从dp[i][j-1]和dp[i-1][j-1]两种情况转移过来,分别表示不选第j把钥匙和第i个人选了第j把钥匙的情况。
可以得到状态转移方程:
dp[i][j]=min(dp[i][j-1],max(dp[i-1][j-1],dis[i][j]));
还有,初始化很重要qwq,所有的dp[0][i]都等于0,剩下的所有都是2147483647。
附上代码
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<math.h>
using namespace std;
int n,k,p;
int man[1005];
int key[2005];
int dis[1005][2005];
int dp[1005][2005];
inline int cmp(int a,int b){
return a<b;
}
int minn(int a,int b){
if(a>=b)return b;
return a;
}
int maxx(int a,int b){
if(a>=b)return a;
return b;
}
int main(){
//freopen("1.in","r",stdin);
cin>>n>>k>>p;
for(register int i=1;i<=n;i++){
cin>>man[i];
}
for(register int i=1;i<=k;i++){
cin>>key[i];
}
sort(man+1,man+n+1,cmp);
sort(key+1,key+k+1,cmp);
for(register int i=0;i<=n;i++){
for(register int j=0;j<=k;j++){
dis[i][j]=fabs(man[i]-key[j])+fabs(key[j]-p);
dp[i][j]=2147483647;
}
}
for(register int i=0;i<=k;i++){
dp[0][i]=0;
}
//cout<<"fuck"<<endl;
for(register int i=1;i<=n;i++){ //1-ige re
for(register int j=1;j<=k;j++){ //1-j zhongxuanze
dp[i][j]=minn(dp[i][j-1],maxx(dp[i-1][j-1],dis[i][j]));
}
}
// while(1){
// int x,y;
// cin>>x>>y;
// cout<<dp[x][y]<<endl;
// }
int ans=2147483647;
for(register int i=n;i<=k;i++){
ans=min(ans,dp[n][i]);
}
cout<<ans<<endl;
}