算法作业(装载问题)

实验六 装载问题

###问题描述与实验目的:
有n个集装箱要装上2艘载重量分别为c1和c2的轮船,其中第i个集装箱的重量为wi,要求确定是否有一个合理的装载方案可将这个集装箱装上这2艘轮船。如果有,找出一种装载方案。
注意,在满足的条件下才可能将这个集装箱装上这2艘轮船。
###输入
输入有若干组测试数据(不超过20组)。
每组测试数据有3行:其第1行上是集装箱个数n,(n<20),第2行上有n个整数w1、w2、…、wn,整数之间用一个空格分开,这n个整数依次表示这n个集装箱的重量,接下来的一行上有2个整数c1、c2,表示这两艘船的载重量,(0<wi <1000,i=1,2,…,n,0<c1,c2<30000)。
###输出
现要求对输入中的每组测试数据,输出2行:
在第1行上输出“Case #”,其中“#”是测试数据的组号(从1开始)。
在第2行上输出具体装载结果:如不能装载则输出“No”;否则输出一个整数bestw及一个由0或1构成的字符串x1x2…xn,其中bestw表示第一艘船能装的最大总载重量,x1x2…xn是对应于bestw的具体装载方案,xi=1表示第i个集装箱装在第一艘船上,而xi=0表示第i个集装箱不装在第一艘船上。
对应于bestw的具体装载方案可能不唯一,如重量分别为10、40、40的3个集装箱,若两船的载重量都是50,那么有装载方案110和101两种。为使输出结果可操作,我们约定长为n的0-1字符串以字典序最大的那个为符合要求的装载方案。
如可能,将计算时间复杂性限制在$ O(2^n)$
###输入样例
3
10 40 40
50 50
3
20 40 40
50 50

###输出
Case 1
50 110
Case 2
No

##分析:
本次实验的重点在于将 O ( n 2 n ) O(n*2^n) 的复杂度优化到$ O(2^n)$,我采用的方法是,在dfs过程中动态的更新路径best。具体实现是:在dfs时记录x[i]和best[i],在回溯的过程中,用x[i]来更新best[i]。
dfs结束以后,看记录的最多可装载量ans+c2与总量之间的关系,如果ans+c2<tot,那么之间输出No,反之,输出ans以及路径。
###运行结果:

Alt text

###源代码:

#include <bits/stdc++.h>
using namespace std;
const int maxn=100;
int n;
int a[maxn];
int c1,c2;
int x[maxn],ans,best[maxn];
int cw;
int ii,r;
void dfs(int i)
{
    if(i>n)
    {
        ii=n;
        ans=cw;
        return;
    }
    r-=a[i];
    if(cw+a[i]<=c1)
    {
        x[i]=1;
        cw+=a[i];
        dfs(i+1);
        if(ii==i) 
        {
            best[i]=1;
            ii--;
        }
        cw-=a[i];
    }
    if(cw+r>ans)
    {
        x[i]=0;
        dfs(i+1);
        if(ii==i)
        {
            best[i]=0;
            ii--;
        }
    }
    r+=a[i];
}
int main()
{
    #ifndef ONLINE_JUDGE
        freopen("in.txt","r",stdin);
        freopen("out.txt","w",stdout);
    #endif
    int Case=0;
    while(scanf("%d",&n)!=EOF)
    {
        if(n==0) break;
        int s=0;
        for(int i=1;i<=n;i++)
        {
            scanf("%d",&a[i]);
            s+=a[i];
        }
        cw=0,ans=0;
        r=s;
        scanf("%d%d",&c1,&c2);
        dfs(1);
        printf("Case %d\n",++Case);
        if(ans+c2<s)
        {
            printf("No\n");
            continue;
        }
        printf("%d  ",ans);
        for(int i=1;i<=n;i++)
        {
            printf("%d",best[i]);
        }
        printf("\n");
    }
    return 0;
}

实验体会
通过本次实验,我对回溯的理解又加深了,也体会到了剪支对搜索算法非常有用。

猜你喜欢

转载自blog.csdn.net/qq_40774175/article/details/83587792