简单数学(一)Greedy——调整+排序+高精

   对于一些排序的最优策略,我们都希望得到一个排序的标准。那么这个标准我们怎么得到呢?

   一个基本的想法是:如果我们交换两个位置,并假设交换后更优,这样便可以得到一个不等式,我们再从不等式中将以i,j为下标的变量分开,这样不等式两边形式相同,只是下标不同,我们便得到了排序规则,利用快排,即可得到最优的序列了。

 

 

 下面是进行排序的代码

int sgn(long long a,long long b){
if(a > b) return 1;
else if(a == b) return 0;
else return -1;
}//用于判断a,b的大小关系

typedef struct minister{
long long a;
long long b;
int d;
}minister;//a记录大臣左手的数,b记录右手的数,d记录a,b的大小关系

int cmp(const void* p1, const void* p2){
minister* p = (minister*)p1;
minister* q = (minister*)p2;
if(p->d!=q->d) return p->d-q->d; //先按a,b大小关系排序
if(p->d<=0 && q->d<=0) return p->a-q->a;//a<b,按a升序排列
return q->b-p->b;//a>b,按b降序排列
}

完整代码如下:

	int T;
	scanf("%d",&T);
	while(T--){
	int n;
	scanf("%d",&n);
        minister* c = (minister*)malloc(sizeof(minister)*n);
        long long ans;
        int i;
        for(i = 0;i < n;i++) 
        {
	scanf("%lld %lld",&c[i].a,&c[i].b);
        c[i].d = sgn(c[i].a,c[i].b);
     	}
     	qsort(c,n,sizeof(minister),cmp);

     	long long s = c[0].a;
     	ans = c[0].a + c[0].b;
     	for(i = 1;i < n;i++){
     	s += c[i].a;
     	ans = max(ans,s)+c[i].b;
     	} 
	  printf("%lld\n",ans);
	
}
return 0;

(PS:我们只考虑相邻的两元素,而不考虑任意的两元素,是因为我们只需要知道充分条件,而由冒泡排序的思想,我们知道这样是正确的)

当然这样的问题可能出现高精的问题。如下题:

类似的考虑我们得到以下排序规则:

typedef struct minister{
    int a;
    int b;
}minister;//a,b分别表示大臣左右手上的数

int cmp(const void* p1,const void* p2){
    minister* p = (minister*)p1;
    minister* q = (minister*)p2;
    if(p->a*p->b > q->a*q->b) return 1;
    else if(p->a*p->b == q->a*q->b) return 0;
    else return -1;
}按照a*b的大小进行排序

高精度乘低精度:

void multiply(char* num1, int x) {
    if(x == 0) return "0";
    if(num1[0] == '0') return "0";
    char tmp;
    char* num2 = (char*)malloc(sizeof(char)*110);
    char *ans = (char*)malloc(sizeof(char)*10000);
    memset(ans,'0',sizeof(char)*10000);
    int i = 0, j, k,max = 0,val = 0,t=0;
    while(x){
    	num2[i] = (x % 10) + '0';
    	x /= 10;
    	i++;
    }
    num2[i] = '\0';
    for(j = 0;j < i / 2;j++){
    	tmp = num2[j];
    	num2[j] = num2[i - 1- j];
    	num2[i-1-j] = tmp;
    }
    
    for(i = strlen(num1) - 1;i >= 0;i--){
        val = 0;
        k = strlen(num1) -1 - i;
        for(j = strlen(num2) - 1;j >= 0;j--){
            t = ans[k] - '0';
            t += (num1[i] - '0')*(num2[j] - '0');
            t +=  val;
            val = t / 10;
            t %= 10;
            ans[k] = t + '0';
            k++;
        }
        
         while(val){
            t = ans[k] - '0';
            t +=  val;
            val = t / 10;
            t %= 10;
            ans[k] = t + '0';
            k++;         	
         }
        if(k > max) max = k;
    }
    ans[max] = '\0';
    for(i = 0;i < max / 2 ;i++){
        tmp = ans[i];
        ans[i] = ans[max - 1 - i];
        ans[max - 1 - i] = tmp;
    }
    for(i = 0;i < max;i++) num1[i] = ans[i];
    num1[i] = '\0';
    free(ans);
    free(num2);
    return ;   
}

 高精度除以低精度:

char* divition(char* num1, int x){
    char tmp;
    char *ans = (char*)malloc(sizeof(char)*strlen(num1));
    memset(ans,'0',sizeof(char)*strlen(num1));
    int i = 0, j, k = 0,max = 0,val = 0,t=0;
    for(i = 0;i < strlen(num1);i++){
        val = val*10 + (num1[i] - '0');
        if(t == 0 && val < x) continue;
        t = 1;
        ans[k] += val / x;
        val %= x;
        k++;
    }
    if(k == 0) k++;
    ans[k] = '\0';
    return ans;
}

完整代码:

char tmp;
int n;
scanf("%d",&n);
int i ,t, len = 0;
minister* v = (minister*)malloc(sizeof(minister)*(n+1));
for(i = 0;i <= n;i++) scanf("%d %d",&v[i].a,&v[i].b);
qsort(v+1,n,sizeof(minister),cmp);//排序

char* left = (char*)malloc(sizeof(char)*10000);
char* ret = (char*)malloc(sizeof(char)*10000);
char* money = (char*)malloc(sizeof(char)*10000);
t = v[0].a;
while(t){
    left[len] = '0' + t % 10;
    t /= 10;
    len++;
}
for(i = 0;i < len/2;i++){
    tmp = left[i];
    left[i] = left[len - 1 - i];
    left[len - 1- i] = tmp;
} 
left[len] = '\0';//初始化左手的乘积

for(i = 1;i <= n;i++){
    ret = divition(left,v[i].b);
    if(i == 1) cpy(money,ret);	
    else{
        if(cp(money,ret) < 0) cpy(money,ret);
    }
    multiply(left,v[i].a);
}//cp其实就是strcmp,cpy就是strcpy。
printf("%s\n",money);
free(left);
free(money);
free(ret);
    return 0;

关于贪心:求数组的最长递增子列,最小生成树。

方法:主要是找到排序规则,可以直接排,也可以先全选,然后排完“后悔”删除一些。 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值