题意:
一列火车有n个座位,它的行驶路线上有m个售票站,对于每个售票站售出的火车票,可以选择全部接受或者全部不接受;每张火车票的价格
为起点与终点站之间的站数差;问这样选择售票站才能使收益最大?
思路:
显然对于每个售票站,都可以选择接受其所有票或者不接受;m<=22 所以可以用dfs穷举所有的方案。具体是:先按起点站对所有售票站按升序排序,用cnt记录当前火车上的人数,sum记录当前的收入,cur记录当前要判断的售票站的编号,vis[]记录每一站应该下车的人数;对于每一个售票站如果满足要求,就可以选择,当然也可以不选,对于其它情况都是不用选择,如此进行dfs。当然这里的重点在于判断当前的售票站是否满足要求,一种方法就是不在每一站对下车的情况进行处理而是通过用cnt-该站之前应该下车的人数是否大于n进行判断;另一种方法是,每一次不管选不选择售票站都对下车的情况进行处理,每次只关注此次的起点站和上次的起点站,这样可以避免重复处理。
反思:
在这种dfs穷举的题目中,进行判断时判断的方式一定也要是可以递归回溯的,否则判断就会出错,比如下面的第三份代码,判断完后直接赋0,就会导致回溯的时候出错。
代码如下:
#include<iostream>
#include<cstring>
#include<cstdio>
#include<algorithm>
using namespace std;
int ans,vis[10],m,total,n;
typedef struct
{
int x,y;
int cnt;
}P;
P p[30];
int cmp(P p1,P p2)
{
if(p1.x==p2.x)
return p1.y<p2.y;
return p1.x<p2.x;
}
int check(int cur,int cnt)
{
int sum=0,i;
for(i=0;i<=p[cur].x;i++)
sum+=vis[i];
if(cnt-sum+p[cur].cnt<=total)
return 1;
return 0;
}
void dfs(int cur,int sum,int cnt)
{
int j;
if(cur==m)
{
if(ans<sum)
ans=sum;
return ;
}
if((check(cur,cnt)))
{
vis[p[cur].y]+=p[cur].cnt;
dfs(cur+1,sum+p[cur].cnt*(p[cur].y-p[cur].x),cnt+p[cur].cnt);
vis[p[cur].y]-=p[cur].cnt;
}
dfs(cur+1,sum,cnt);
}
int main()
{
int i,j;
while(scanf("%d%d%d",&total,&n,&m))
{
if(total==0&&n==0&&m==0)
break;
for(i=0;i<m;i++)
{
scanf("%d%d%d",&p[i].x,&p[i].y,&p[i].cnt);
}
sort(p,p+m,cmp);
ans=0;
memset(vis,0,sizeof(vis));
dfs(0,0,0);
printf("%d\n",ans);
}
return 0;
}
代码2:
#include<iostream>
#include<cstring>
#include<cstdio>
#include<algorithm>
using namespace std;
int ans,vis[10],m,total,n;
typedef struct
{
int x,y;
int cnt;
}P;
P p[30],p1;
int cmp(P p1,P p2)
{
if(p1.x==p2.x)
return p1.y<p2.y;
return p1.x<p2.x;
}
void dfs(int cur,int sum,int cnt,int pre)
{
int j;
if(cur==m)
{
if(ans<sum)
ans=sum;
return ;
}
//无论这个车站上不上人,下车都是必须的
for(j=pre+1;j<=p[cur].x;j++)
cnt-=vis[j];
if(cnt+p[cur].cnt<=total)
{
vis[p[cur].y]+=p[cur].cnt;
dfs(cur+1,sum+p[cur].cnt*(p[cur].y-p[cur].x),cnt+p[cur].cnt,p[cur].x);
vis[p[cur].y]-=p[cur].cnt;
}
dfs(cur+1,sum,cnt,p[cur].x);
}
int main()
{
int i,j;
while(scanf("%d%d%d",&total,&n,&m))
{
if(total==0&&n==0&&m==0)
break;
for(i=0;i<m;i++)
{
scanf("%d%d%d",&p[i].x,&p[i].y,&p[i].cnt);
}
sort(p,p+m,cmp);
ans=0;
memset(vis,0,sizeof(vis));
dfs(0,0,0,0);
printf("%d\n",ans);
}
return 0;
}
错误代码:
#include<iostream>
#include<cstring>
#include<cstdio>
#include<algorithm>
using namespace std;
int ans,vis[10],m,total,n;
typedef struct
{
int x,y;
int cnt;
}P;
P p[30],p1;
int cmp(P p1,P p2)
{
if(p1.x==p2.x)
return p1.y<p2.y;
return p1.x<p2.x;
}
void dfs(int cur,int sum,int cnt)
{
int j;
if(cur==m)
{
if(ans<sum)
ans=sum;
return ;
}
//无论这个车站上不上人,下车都是必须的
//下车之后记得将相应车站人数清0
for(j=0;j<=p[cur].x;j++)
{
cnt-=vis[j];
vis[j]=0;//赋0操作导致回溯出错
}
if(cnt+p[cur].cnt<=total)
{
vis[p[cur].y]+=p[cur].cnt;
dfs(cur+1,sum+p[cur].cnt*(p[cur].y-p[cur].x),cnt+p[cur].cnt);
vis[p[cur].y]-=p[cur].cnt;
}
dfs(cur+1,sum,cnt);
}
int main()
{
int i,j;
while(scanf("%d%d%d",&total,&n,&m))
{
if(total==0&&n==0&&m==0)
break;
for(i=0;i<m;i++)
{
scanf("%d%d%d",&p[i].x,&p[i].y,&p[i].cnt);
}
sort(p,p+m,cmp);
ans=0;
memset(vis,0,sizeof(vis));
dfs(0,0,0);
printf("%d\n",ans);
}
return 0;
}