从加工生产调度看邻项交换问题

题目链接

这类题目显然是邻项交换,但是有要注意的点。

先用邻项交换的方法跑一边,发现\(cmp\)函数为:\(x.a+max(x.b,y.a)+y.b < y.a+max(y.b,x.a)+x.b\)

其实可以化简:\(min(x.a,y.b)<min(x.b,y.a)\)(因为\(max(x,y)-x-y=-min(x,y)\)

但是这是一个错的排序方式,所以说这个证明及其完全我就不写了

我感性理解了一下,就是化简后有\(max,min\)函数之类的好像都不行。

网上很多人说这个式子没有传递性,实际上这个式子不满足不可比的传递性。

而这个传递性可以理解成三个元素\(a,b,c\)对于某个不等关系满足\(a=b,b=c\Rightarrow a=c\)。(这是个不完全的理解,但暂时可以这么理解,泛用性应该还不差)

实际上,我们这样带有\(max,min\)函数的式子一般不满足,拿此题来说对于以下的三个产品就不满足:

7 3
1 1
1 6

至此我们先强调一点,我并没有说\(Johnson\)算法是错的,实际上从原理上来说,这个要求是完全正确,也就是说,我们的最优排序方案一定满足这个式子,用这个式子人工排序也一定能成,但是在计算机中行,因为sort的排序方式是一定会满足不可比的传递性,也就是说两个数相等对其顺序没有影响,但是这种排序方式不一定,所以我们要将其转化,化为满足不可比的传递性的形式。

换句话说,我们要找到一种等价的比较方式,使的无论什么情况下均满足上面的式子且具有不可比的传递性。

转换的时候实际上我们并不是说完全抛弃掉原来的方式,观察\(Hack\)样例,实际上就是当有\(a_i==b_i\)时会出锅。

也就是说,我们将这种情况单独领出来考虑即可:

  • \(a_i<b_i\&\&a_j=b_j\)时不用交换(分类讨论)
  • \(a_i>b_i\&\&a_j=b_j\)时需要交换(分类讨论)

所以我们得到了如下的分类(每一类的顺序即为其优先级):

  • \(a_i<b_i\&\&a_j<b_j\),这时可以用\(min(x.a,y.b)<min(x.b,y.a)\)(或者你可以说按照\(a_i<a_j\)排序,因为你分类讨论之后发现这两者一样)
  • \(a_i=b_i\),这时随意(自行讨论)。
  • \(a_i>b_i\&\&a_j>b_j\),这时可以用\(min(x.a,y.b)<min(x.b,y.a)\)(或者你可以说按照\(b_i>b_j\)排序,因为你分类讨论之后发现这两者一样)

这时我们就可以写了。

#include<bits/stdc++.h>
using namespace std;
#define int long long
inline int read()
{
    int f=1,w=0;char x=0;
    while(x<'0'||x>'9') {if(x=='-') f=-1; x=getchar();}
    while(x!=EOF&&x>='0'&&x<='9') {w=(w<<3)+(w<<1)+(x^48);x=getchar();}
    return w*f;
}
const int N=20010;
int n,f[N];
struct Person
{
    int x,y,d,id;
    bool operator < (const Person &b)
        {
            return d==b.d?min(x,b.y)<min(y,b.x):d<b.d;
        }
}p[N];
main(){
#ifndef ONLINE_JUDGE
    freopen("A.in","r",stdin);
#endif
    n=read();
    for(int i=1;i<=n;i++) p[i].x=read(),p[i].id=i;
    for(int i=1;i<=n;i++)
    {
        p[i].y=read();
        p[i].d=p[i].x<p[i].y?-1:p[i].x>p[i].y?1:0;
    }
    sort(p+1,p+n+1);
    int Ta=p[1].x,Tb=p[1].x+p[1].y;
    for(int i=2;i<=n;i++) Tb=max(Ta+p[i].x,Tb)+p[i].y,Ta+=p[i].x;
    printf("%lld\n",Tb);
    for(int i=1;i<=n;i++) printf("%lld ",p[i].id);
}

其实还有一种做法:我们发现\(Tb=max(Ta+p[i].x,Tb)+p[i].y,Ta+=p[i].x;\)是我们求答案的过程。

就是(懒得打了)

没错,就是皇后游戏,观察全局,发现和\(a_i\)的大小有关,因此当我们判到\(min(x.a,y.b)=min(x.b,y.a)\)时,可以按照\(a_i<a_j\)的顺序排序(应该本质上是一样的,只是这样更好理解。)

皇后游戏的代码:

#include<bits/stdc++.h>
using namespace std;
#define int long long
inline int read()
{
    int f=1,w=0;char x=0;
    while(x<'0'||x>'9') {if(x=='-') f=-1; x=getchar();}
    while(x!=EOF&&x>='0'&&x<='9') {w=(w<<3)+(w<<1)+(x^48);x=getchar();}
    return w*f;
}
const int N=20010;
int n,f[N];
struct Person
{
    int x,y;
    bool operator < (const Person &b)
        {
            return min(x,b.y)==min(y,b.x)?x<b.x:min(x,b.y)<min(y,b.x);
        }
}p[N];
main(){
#ifndef ONLINE_JUDGE
    freopen("A.in","r",stdin);
#endif
    int T=read();
    while(T--)
    {
        int Tot=0,ans=0;n=read();
        for(int i=1;i<=n;i++) p[i].x=read(),p[i].y=read();
        sort(p+1,p+n+1);
        for(int i=1;i<=n;i++)
            Tot+=p[i].x,ans=max(ans,Tot)+p[i].y;
        printf("%lld\n",ans);
    }
}

猜你喜欢

转载自www.cnblogs.com/wo-shi-zhen-de-cai/p/11553033.html