又是一个典型的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; } } }