uva--301+dfs回溯穷举

来源:互联网 发布:特朗普穆斯林禁令知乎 编辑:程序博客网 时间:2024/06/05 04:59

题意:

    一列火车有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;}


  

0 0
原创粉丝点击