竞赛题一例

本文介绍了一个有效算法,用于计算在给定汽车行驶距离和加油站分布的情况下,如何在最少的加油站停靠加油,以确保到达目的地。

题目:

一辆汽车加满油后,可行使n千米。旅途中有若干个加油站。若要使沿途加油次数最少,设计一个有效算法,对于给定的n和k个加油站位置,指出应在那些加油站停靠加油才能使加油次数最少。输入数据中,第一行有2个正整数,分别表示汽车加满油后可行使n千米,且旅途中有k个加油站。接下来的1行中,有k+1个整数,表示第k个加油站与第k-1个加油站之间的距离。第0个加油站表示出发地,汽车已加满油。第k+1个加油站表示目地地。输出为最少的加油次数,如果无法到达目的地,则输出“No Solution”。
    提示:
    把两加油站的距离放在数组中,a[1..k]表示从起始位置开始跑,经过k个加油站,a[i]表示第i-1个加油站到第i个加油站的距离。汽车在运行的过程中如果能跑到下一个站则不加油,否则要加油。
输入数据示例
7  7
1  2  3  4  5  1  6  6
输出数据
4

-----------------

解法:

从整数线性规划的角度出发,以上题为例,即加满汽油可以走7公里,一共有7个加油站。
7  7
1  2  3  4  5  1  6  6
现在我设一组变量a1,a2,a3,a4,a5,a6,a7,这7个变量只能取0或1,如果取1表汽车在该站加油,否则表示汽车没在该站加油。
那么我的目标函数是求 a1+a2+a3+a4+a5+a6+a7的最小值。
再设一组变量x1,x2,x3,x4,x5,x6,x7,x8表示汽车到达该加油站之后,剩下的汽油所能行走的路程。x8表示汽车在到达终点后所剩下汽油所能行走的路程。
那么x1~x7必须满足使汽车可以开到下一站,同时x8>=0
x1 = 7*a1 + (1-a1)*(7-1) >= 2
x2 = 7*a2 + (1-a2)*(x1-2) >= 3
x3 = 7*a3 + (1-a3)*(x2-3) >= 4
x4 = 7*a4 + (1-a4)*(x3-4) >= 5
x5 = 7*a5 + (1-a5)*(x4-5) >= 1
x6 = 7*a6 + (1-a6)*(x5-1) >= 6
x7 = 7*a7 + (1-a7)*(x6-6) >= 6
x8 = x7-6 >= 0
根据上述约束条件,求解目标方程 a1+a2+a3+a4+a5+a6+a7的最小值

程序如下:

#include <stdio.h>
#include <stdlib.h>

#define N 1024

int full; //加满油时能走的路程
int num;  //加油站个数
int distance[N]={0}; //加油站见的距离
int isAdd[N]={0};    //只能取0或1,表示汽车在该站点是否加油
int remain[N]={0};  //汽车所剩下的油所能走的路程
int min=0;
int onSol=1;        //该值为1表示无解
void fun(int index);

int main()
{
    int i;
    scanf("%d",&full);
    scanf("%d",&num);
    for(i=0;i<=num;++i){
        scanf("%d",distance+i);
    }
    min=num;
    remain[0]=full;
    if(remain[0]<distance[0]){
        printf("No Solution");
        return 0;
    }
    fun(0);
    if(onSol) printf("No Solution");
    else printf("%d",min);
    return 0;
}

void fun(int index)
{
    int i;
    int tmp;
    if(index>num){
        onSol=0;
        tmp = 0;
        for(i=0;i<num;++i){
            tmp += isAdd[i];
        }
        if(tmp < min){
            min=tmp;
            //for(i=0;i<num;++i){
            //    if(isAdd[i]!=0){
            //        printf("%d ",i);
            //    }
            //}
            //printf(":%d\n",tmp);
        }
        return;
    }
    for(i=0;i<2;++i){
        isAdd[index]=i;
        remain[index+1] = full*i + (1-i)*(remain[index]-distance[index]);
        if(remain[index+1]>=distance[index+1]){
            fun(index+1);
        }
    }
}


 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值