对于一些排序的最优策略,我们都希望得到一个排序的标准。那么这个标准我们怎么得到呢?
一个基本的想法是:如果我们交换两个位置,并假设交换后更优,这样便可以得到一个不等式,我们再从不等式中将以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;
关于贪心:求数组的最长递增子列,最小生成树。
方法:主要是找到排序规则,可以直接排,也可以先全选,然后排完“后悔”删除一些。