首页 > 代码库 > Codeforces 830A. Office Keys (背包dp+贪心) / (二分+贪心)

Codeforces 830A. Office Keys (背包dp+贪心) / (二分+贪心)

题目链接:

http://codeforces.com/problemset/problem/830/A

题意:

n个人,k个钥匙(n<=k),p表示这些人要到达的位置

给出n个人的位置以及钥匙的位置,问花时间最多的那个人用时最少是多少??

思路:

二分+贪心: 二分最少时间,需要对a,b位置数组排序,我们check函数只需要从左到右一个一个找过去,因为如果选后边的点,可能会使结果更差,假如当前这个人选后面的点,那可能会选中后面的人可以选的唯一的钥匙,不会使解更优。

技术分享

check(40)的时候答案是false,是错误的,因为第一个人把第二个人可以唯一选的钥匙选上了。

复杂度是 O((n+k)*log(2e9))

dp+贪心: 

dp[i][j]表示前i个人用前j把钥匙
转移: dp[i][j] = min(dp[i][j-1],max(dp[i-1][j-1],abs(a[i]-b[j])+abs(b[j]-p)));
dp[i][j-1]: 表示不选第 j 把钥匙
max(dp[i-1][j-1],abs(a[i]-b[j])+abs(b[j]-p)): 表示选第 j 把钥匙,就是考虑前 i-1 个人用前 j-1 把钥匙,第i个人用第j把钥匙,取最长的时间,因为答案要最长的人的时间
显然 取二者最小就是答案了  ----》 背包?

dp真奇妙啊!

代码一:

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
#define MS(a) memset(a,0,sizeof(a))
#define MP make_pair
#define PB push_back
const int INF = 0x3f3f3f3f;
const ll INFLL = 0x3f3f3f3f3f3f3f3fLL;
inline ll read(){
    ll x=0,f=1;char ch=getchar();
    while(ch<0||ch>9){if(ch==-)f=-1;ch=getchar();}
    while(ch>=0&&ch<=9){x=x*10+ch-0;ch=getchar();}
    return x*f;
}
//////////////////////////////////////////////////////////////////////////
const int maxn = 2e3+10;

ll dp[maxn][maxn],a[maxn],b[maxn];

int main(){
    int n,k,p;
    cin >> n >> k >> p;
    for(int i=1; i<=n; i++)
        cin >> a[i];
    for(int i=1; i<=k; i++)
        cin >> b[i];
    sort(a+1,a+1+n);
    sort(b+1,b+1+k);
    for(int i=0; i<=n; i++)
        for(int j=0; j<=k; j++)
            dp[i][j] = INFLL;
    for(int i=0; i<=k; i++) dp[0][i]=0;
    for(int i=1; i<=n; i++)
        for(int j=i; j<=k; j++){
            dp[i][j] = min(dp[i][j-1],max(dp[i-1][j-1],abs(a[i]-b[j])+abs(b[j]-p)));
        }
    cout << dp[n][k] << endl;


    return 0;
}

 

代码二:

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
#define MS(a) memset(a,0,sizeof(a))
#define MP make_pair
#define PB push_back
const int INF = 0x3f3f3f3f;
const ll INFLL = 0x3f3f3f3f3f3f3f3fLL;
inline ll read(){
    ll x=0,f=1;char ch=getchar();
    while(ch<0||ch>9){if(ch==-)f=-1;ch=getchar();}
    while(ch>=0&&ch<=9){x=x*10+ch-0;ch=getchar();}
    return x*f;
}
//////////////////////////////////////////////////////////////////////////
const int maxn = 2e3+10;

int n,k,pos;
ll a[maxn],b[maxn];
bool used[maxn];

bool check(ll x){
    int p = 0;
    for(int i=1; i<=n; i++){
        while(p<=k){
            p++;
            if(1LL*(abs(a[i]-b[p])+abs(b[p]-pos))<=x) break;
        }
        if(p > k) return false;
    }
    return true;
}

int main(){
    cin >> n >> k >> pos;
    for(int i=1; i<=n; i++)
        a[i] = read();
    for(int i=1; i<=k; i++)
        b[i] = read();
    sort(a+1,a+n+1); sort(b+1,b+k+1);

    ll L=0,R=2e9,ans=INFLL;
    while(L<=R){
        ll mid = (L+R)/2;
        if(check(mid)) ans=mid,R=mid-1;
        else L = mid+1;
    }
    cout << ans << endl;


    return 0;
}

 

Codeforces 830A. Office Keys (背包dp+贪心) / (二分+贪心)