1. 程式人生 > >貪心+高精度【洛谷P1080】

貪心+高精度【洛谷P1080】

此篇文章的程式碼來自@Chlience,未經允許私自借用,十分不好意思。

題目連結:https://www.luogu.org/problemnew/show/P1080

 

拿到這個題目,我根本沒有注意到資料範圍竟然會超long long,真的是第一次做這種貪心題竟然需要寫高精度。(做的題太少了,所以沒見過,所以蒻)

首先推導一下貪心的策略:(借鑑自@Chlience)

簡化一下問題,假如只有國王和兩個大臣,總共三個人:如下圖

king a0 b0
p1 a1 b1
p2 a2 b2

此時ans1 = max(a0/b1,(a0*a1)/b2)

king a0 b0

p2

a2 b2
p1 a1 b1

此時ans2 = max(a0/b2,(a0*a2)/b1)

顯然可以化簡為ans1 = max(k1,k2)

                         ans2 = max(k3,k4)

則有 k2>k3, k4>k1

若ans1<ans2

則 k4>k2

則 (a0*a2)/b1>(a0*a1)/b2

變換得:a1*b1<a2*b2

至此,我們得出了cmp()函式的寫法。

 

然後,在此奉上@Chlience的程式碼:

#include <bits/stdc++.h>
using namespace std;
int now[20010],sum[20010],ans[20010],add[20010];
struct Node {
    int a;
    int b;
    long long a_b;
}node[1010];
void times(int x) {
    memset(add,0,sizeof(add));
    for(int i=1;i<=ans[0];i++) {
        ans[i]=ans[i]*x;
        add[i+1]+=ans[i]/10;
        ans[i]%=10;
    }
    for(int i=1;i<=ans[0]+4;i++) {
        ans[i]+=add[i];
        if(ans[i]>=10) {
            ans[i+1]+=ans[i]/10;
            ans[i]%=10;
        }
        if(ans[i]!=0) {
            ans[0]=max(ans[0],i);
        } 
    }
    return ;
}
int divition(int x) {
    memset(add,0,sizeof(add));
    int q=0;
    for(int i=ans[0];i>=1;i--) {
        q*=10;
        q+=ans[i];
        add[i]=q/x;
        if(add[0]==0 && add[i]!=0) {
            add[0]=i;
        }
        q%=x; 
    }
    return 0;
}
bool compare() {
    if(sum[0]==add[0]) {
        for(int i=add[0];i>=1;i--) {
            if(add[i]>sum[i]) return 1;
            if(add[i]<sum[i]) return 0;
        }
    }
    if(add[0]>sum[0]) return 1;
    if(add[0]<sum[0]) return 0;
}
void cp () {
    memset(sum,0,sizeof(sum));
    for(int i=add[0];i>=0;i--) {
        sum[i]=add[i];
    }
    return ;
}
bool cmp(Node a,Node b) {
    return a.a_b<b.a_b;
}
int main() {
	int n;
    cin>>n;
    for(int i=0;i<=n;i++) {
        cin>>node[i].a>>node[i].b;
        node[i].a_b=node[i].a*node[i].b;
    }
    sort(node+1,node+n+1,cmp);
    ans[0]=1,ans[1]=1;
    for(int i=1;i<=n;i++) {
        times(node[i-1].a);
        divition(node[i].b);
        if(compare()) {
            cp();
        }
    }
    for(int i=sum[0];i>=1;i--)
        printf("%d",sum[i]);
    return 0;
} 

自己還是太蒻了,高精度板子會寫(抄),放在實際的應用裡面就一團亂。