又是一个典型的dfs加剪枝的搜索的题目:
题目大意:从A站到B站,共n个车站,每个车站可以有不同的上车人数的请求,见题目的描述。
问题:在所有的ticket order过程中,可以获得的最大利润。
1、我用回溯法,进行暴力求解,写得比较简单,没有什么技术含量,且效率是比较低下的,1000MS一次水过,下面会附上代码:
2、后来采用了dfs的方法,加了一个剪枝,16MS,这个算是比较过得去。
分析:
struct Data
{
int x; // start station
int y; // end station
int p; // number of passengers
int v; // profit of the order
int r; // the maximum profit by accept the order
};
解释一下int r在这里的作用,这里用于搜索中的剪枝
1)先按利润的大小值进行排序
2)初始化每个节点的r值,第i个节点的r值在这里表示的意思是:若第i个节点后,理论上可以达到的最大利润值的大小。这个条件可以用来剪枝,而且效果非常明显。
下面dfs方式实现的代码:
/* poj 1040 , wrote by Dream Chen 2010/12/11 */
#include <cstdio>
#include <string>
#include <algorithm>
using namespace std;
struct Data
{
int x; // start station
int y; // end station
int p; // number of passengers
int v; // profit of the order
int r; // the maximum profit by accept the order
};
Data data[50];
int capacity = 0;
int station = 0;
int order = 0;
int stop[50];
int maxp = 0;
void Initial(void);
inline bool cmp(const Data &a, const Data &b)
{
return a.v > b.v;
}
void dfs(int s,int curMaxp);
int main(void)
{
//freopen("input.txt","r",stdin);
while(scanf("%d%d%d",&capacity,&station,&order) && !(capacity == 0 && station == 0 && order == 0))
{
Initial();
for (int i = 0; i < order; ++i)
{
scanf("%d%d%d",&data[i].x, &data[i].y, &data[i].p);
data[i].v += (data[i].y - data[i].x) * data[i].p;
}
sort(data,data+order,cmp);
for (int i = order - 1, sum = 0; i >= 0; --i)
{
sum += data[i].v;
data[i].r = sum;
}
maxp = 0;
dfs(0,0);
printf("%d/n",maxp);
}
return 0;
}
void Initial(void)
{
memset((void*)data,0,sizeof(data));
memset((void*)stop,0,sizeof(stop));
maxp = 0;
}
void dfs(int s,int curMaxp)
{
if (curMaxp > maxp)
{
maxp = curMaxp;
}
if (s >= order)
{
return;
}
/* If accept this order, curMaxp + data[s].r < maxp ,
it means that this solution can't be the optimal solution
It's very important here!!!
*/
if (curMaxp + data[s].r < maxp)
{
return;
}
for (int i = s, j = 0; i < order; ++i)
{
for (j = data[i].x; j < data[i].y; ++j)
{
stop[j] += data[i].p;
if (stop[j] > capacity)
{
break;
}
}
if (j == data[i].y)
{
dfs(i+1,curMaxp+data[i].v);
--j;
}
// traceback here
for (int k = j; k >= data[i].x; --k)
{
stop[k] -= data[i].p;
}
}
}
下面是用回溯法暴搜的代码:
/* poj 1040, wrote by Dream Chen 2010/11/30*/
#include <cstdio>
#include <string>
using namespace std;
struct Data
{
int start;
int dst;
int num_psng;
};
int icapacity = 0;
int ibstation = 0;
int iticket = 0;
Data data[30];
int res = 0;
int cur_num = 0;
bool bflag[30];
int arr_psng_num[30];
void Initial(void);
void TrySearch(int cur);
bool Test(int i);
void AddOrder(int cur);
void RemoveOrder(int cur);
int main(void)
{
while(scanf("%d%d%d", &icapacity, &ibstation, &iticket) != 0)
{
if (0 == icapacity && 0 == ibstation && 0 == iticket)
{
break;
}
Initial();
for (int i = 0; i < iticket; ++i)
{
scanf("%d%d%d",&data[i].start,&data[i].dst,&data[i].num_psng);
}
TrySearch(0);
printf("%d/n",res);
}
return 0;
}
void Initial(void)
{
memset((void*)data,0,sizeof(data));
memset((void*)arr_psng_num,0,sizeof(arr_psng_num));
res = 0;
cur_num = 0;
}
void TrySearch(int cur)
{
if (cur >= iticket)
{
return;
}
if (Test(cur))
{
AddOrder(cur);
TrySearch(cur+1);
RemoveOrder(cur);
}
TrySearch(cur+1);
}
bool Test(int i)
{
for (int j = data[i].start; j < data[i].dst; ++j)
{
if (arr_psng_num[j] + data[i].num_psng > icapacity)
{
return false;
}
}
return true;
}
void AddOrder(int cur)
{
bflag[cur] = true;
if (cur >= 0 && cur < iticket)
{
for (int j = data[cur].start; j < data[cur].dst; ++j)
{
arr_psng_num[j] += data[cur].num_psng;
cur_num += data[cur].num_psng;
}
}
if (cur_num > res)
{
res = cur_num;
}
}
void RemoveOrder(int cur)
{
bflag[cur] = false;
if (cur >= 0 && cur < iticket)
{
for (int j = data[cur].start; j < data[cur].dst; ++j)
{
arr_psng_num[j] -= data[cur].num_psng;
cur_num -= data[cur].num_psng;
}
}
}