题目:
一辆汽车加满油后,可行使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);
}
}
}