10.2 test solution.

本文解析了三道算法竞赛题目,包括求解特定数学序列、树上的路径最大权值问题及优化卡包开箱策略,提供了详细的解题思路与代码实现。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1.a(a.cpp/c/pas)

时空限制

时间限制

1s

空间限制

256MB

【问题描述】

你是能看到第一题的 friends呢。—— hja

世界上没有什么比卖的这么贵的弹丸三还令人绝望的事了,所以便有了这么一道题。定义f(x)为满足 (a×b)x的有序正整数对(a,b)的个数。
现在给定N,求i=1Nf(i)

【输入格式】

一行个整数N

【输出格式】

一行个整数代表答案 。

【样例输入】

6

【样例输出】

25

【数据范围与规定】

对于 30%的数据, 1N100
对于 60%的数据, 1N1000
对于 100%的数据,1N1011


solution

  • 60分思路

    • 胡乱找一下规律,发现ans=i=1N(n/i)d(i)
    • 其中d(i)表示 i 的约数个数

    • 然后n/i可以除法分块,d(i)的前缀和也可以除法分块,然后乱搞一下就好了。

    • 怎么推出来并不重要反正只有60分
  • 100分思路

    • 如果一个正整数对(a,b)满足(a×b)x,那就有x=a×b×c
    • 那问题就转换成了找三个正整数a,b,c,满足a×b×c=x的方案数
    • 因为题目求的是i=1Nf(i) ,所以a×b×cN就行,因为只要a×b×cN,这三个正整数就对答案有贡献
    • 所以枚举a,b,c,满足条件,ans++,但这样是O(n3),稳TLE
    • 考虑一种满足条件的a,b,c,这三个整数有 6 种排列,而且这 6 种排列都满足条件
    • 所以可以强行让abc,这样枚举并且统计答案,最后再6就好了
    • 但是还有一种情况是a,b,c三个数有可能有相同的数,所以再把这些情况枚举一下

    • 两个数相同,一共有3种排列,三个数相同,只有1种排列

    • 最后把这些情况都加起来就是最后的答案,时间复杂度据zhx说O(n56)

code

  • test 60分代码
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
typedef long long ll;

template<typename T>
void input(T &x) {
    x=0; T a=1;
    register char c=getchar();
    for(;c<'0'||c>'9';c=getchar())
        if(c=='-') a=-1;
    for(;c>='0'&&c<='9';c=getchar())
        x=x*10+c-'0';
    x*=a;
    return;
}

ll n;

ll Getd(ll n) {
    ll ret=0;
    for(ll l=1,r;l<=n;l=r+1) {
        r=n/(n/l);
        ret+=(n/l)*(r-l+1);
    }
    return ret;
}

ll sum(ll n) {
    ll ret=0;
    for(ll l=1,r;l<=n;l=r+1) {
        r=n/(n/l);
        ret+=(n/l)*(Getd(r)-Getd(l-1));
    }
    return ret;
}

int main() {
    freopen("a.in","r",stdin);
    freopen("a.out","w",stdout);
    input(n);
    printf("%lld\n",sum(n));
    fclose(stdin);
    fclose(stdout);
    return 0;
}
  • 100分code 其实也没那么难
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
typedef long long ll;

int main() {
    freopen("a.in","r",stdin);
    freopen("a.out","w",stdout);
    ll n;
    scanf("%lld",&n);
    ll ans=0,tans=0;
    /*
    for循环里面的ans++就是统计的三个数都相同的情况
    */
    for(ll a=1,v;a*a<=(v=n/a);a++,ans++)
        for(ll b=a+1;b*b<=v;b++)
            tans+=n/(a*b)-b;
    /*
    tans+=的那个东西,是c的所有取值的情况
    a*b*c<=n
    c<=n/(a*b)
    因为我们规定了a<=b<=c
    所以b<=c<=n/(a*b)
    所以c的取值一共有n/(a*b)-b种
    */
    ans+=tans*6;
    tans=0;
    /*
    下面是两个数相同的情况
    和上面类似
    */
    for(ll a=1,v;(v=a*a)<=n;a++) {
        tans+=n/v;
        if(a*a<=n/a) tans--;
    }
    ans+=tans*3;
    printf("%lld\n",ans);
    return 0;
}

2.b(b.cpp/c/pas)

时空限制

时间限制

1s

空间限制

256MB

【问题描述】

你是能看到第二题的 friends呢。—— laekov

Hja和 Yjq为了抢男主角打了起来,现在他们正在一棵树上决斗 。Hja在 A点,Yjq在 B点,Hja先发制人开始移动 。每次他们可以沿着一条边移动 ,但 一旦一条边被对方走过了自己就不能再走这条边了。每条边上都有权值 ,他们都希望自己的权值尽量多 。现在给你这棵树以及他们俩开始的位置 ,问Hja能够获得的最大权值 。

【输入格式】

第一行两个整数 N,M,代表树的点数和询问的个数 。
接下来N1行每行三个整数a,b,c,代表从ab有一条权值为c的边 。
接下来M行,每行两个整数A,B代表一次询问 。

【输出格式】

对于每次询问 ,输出一个整数代表答案 。

【样例输入1】

2 1
1 2 3
1 2

【样例输出1】

3

【样例输入2】

3 2
1 2 3
1 3 1
2 3
1 3

【样例输出2】

3
4

【数据范围与规定】

对于30%的数据 ,1N,M1000
对于另外30%的数据 ,M=1
对于100%的数据,1N,M105,0c103,1a,b,A,BN

solution

code

  • std by zhx
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<algorithm>

using namespace std;

const int maxn=100010;

int n,m,en,z[maxn*3],f[maxn][20],q[maxn],depth[maxn],sum[maxn*3][2],fd[maxn],start[maxn],end[maxn],value[maxn];

struct edge
{
    int e,d;
    edge *next;
}*v[maxn],ed[maxn<<1];

void add_edge(int s,int e,int d)
{
    en++;
    ed[en].next=v[s];v[s]=ed+en;v[s]->e=e;v[s]->d=d;
}

int get(int p,int d)
{
    if (d==-1) return p;
    int x=0;
    while (d)
    {
        if (d&1) p=f[p][x];
        d>>=1;
        x++;
    }
    return p;
}

int get_lca(int p1,int p2)
{
    if (depth[p1]<depth[p2]) swap(p1,p2);
    p1=get(p1,depth[p1]-depth[p2]);
    int x=0;
    while (p1!=p2)
    {
        if (!x || f[p1][x]!=f[p2][x])
        {
            p1=f[p1][x];
            p2=f[p2][x];
            x++;
        }
        else x--;
    }
    return p1;
}

int calc(int p1,int p2)
{
    if (p1==f[p2][0]) return value[1]-value[p2];
    else return value[p1]+fd[p1];
}

int calcp(int p,int v)
{
    int l=start[p]-1,r=end[p];
    while (l+1!=r)
    {
        int m=(l+r)>>1;
        if (v>z[m]) l=m;
        else r=m;
    }
    return r;
}

int main()
{
    freopen("b.in","r",stdin);
    freopen("b.out","w",stdout);

    scanf("%d%d",&n,&m);
    int tot=0;
    for (int a=1;a<n;a++)
    {
        int s,e,d;
        scanf("%d%d%d",&s,&e,&d);
        tot+=d;
        add_edge(s,e,d);
        add_edge(e,s,d);
    }
    depth[1]=1;
    int front=1,tail=1;
    q[1]=1;
    for (;front<=tail;)
    {
        int now=q[front++];
        for (edge *e=v[now];e;e=e->next)
            if (!depth[e->e])
            {
                depth[e->e]=depth[now]+1;
                fd[e->e]=e->d;
                f[e->e][0]=now;
                int p=now,x=0;
                while (f[p][x])
                {
                    f[e->e][x+1]=f[p][x];
                    p=f[p][x];
                    x++;
                }
                q[++tail]=e->e;
            }
    }
    int cnt=0;
    for (int a=n;a>=1;a--)
    {
        int now=q[a];
        start[now]=cnt+1;
        for (edge *e=v[now];e;e=e->next)
            if (depth[e->e]==depth[now]+1)
            {
                z[++cnt]=value[e->e]+e->d;
                value[now]+=value[e->e]+e->d;
            }
        z[++cnt]=tot-value[now];
        end[now]=cnt;
        sort(z+start[now],z+end[now]+1);
        sum[end[now]][0]=z[end[now]];
        sum[end[now]][1]=0;
        for (int a=end[now]-1;a>=start[now];a--)
        {
            sum[a][0]=sum[a+1][0];
            sum[a][1]=sum[a+1][1];
            if ((a&1)==(end[now]&1)) sum[a][0]+=z[a];
            else sum[a][1]+=z[a];
        }
        cnt++;
    }
    for (int a=1;a<=m;a++)
    {
        int p1,p2;
        scanf("%d%d",&p1,&p2);
        int lca=get_lca(p1,p2);
        int dist=depth[p1]+depth[p2]-2*depth[lca];
        int delta=dist/2+(dist&1);
        int px,px1,px2;
        if (depth[p1]-depth[lca]<delta) px=get(p2,dist-delta);
        else px=get(p1,delta);
        if (depth[p1]-depth[lca]<delta-1) px1=get(p2,dist-delta+1);
        else px1=get(p1,delta-1);
        if (depth[p2]-depth[lca]<dist-delta-1) px2=get(p1,delta+1);
        else px2=get(p2,dist-delta-1);
        int ans=0;
        if (p1==px)
        {
            if (p2==px) ans=sum[start[px]][0];
            else
            {
                int v2=calc(px2,px);
                int p=calcp(px,v2);
                ans=sum[p+1][0]+sum[start[px]][1]-sum[p][1];
            }
        }
        else
        {
            if (p2==px)
            {
                int v1=calc(px1,px);
                int p=calcp(px,v1);
                ans=v1+sum[p+1][1]+sum[start[px]][0]-sum[p][0];
            }
            else
            {
                int v1=calc(px1,px);
                int pp1=calcp(px,v1);
                int v2=calc(px2,px);
                int pp2=calcp(px,v2);
                if (pp2==pp1) pp2++;
                if (pp1>pp2) swap(pp1,pp2);
                ans=v1+sum[pp2+1][dist&1]+sum[pp1+1][1-(dist&1)]-sum[pp2][1-(dist&1)]+sum[start[px]][dist&1]-sum[pp1][dist&1];
            }
        }
        printf("%d\n",ans);
    }

    return 0;
}

3.c(c.cpp/c/pas)

时空限制

时间限制

1s

空间限制

256MB

【问题描述】

你是能看到第三题的 friends呢。—— aoao

Yjq买了36个卡包,并且把他们排列成6×6的阵型准备开包 。左上角是(0,0),右下角为 (5,5)。为了能够开到更多的金色普通卡,Yjq会为每个包添加 1-5个玄学值,每个玄学值可以是 1-30中的一个整数。但是不同的玄学值会造成不同的欧气加成,具体如下:

  1. 同一个卡包如果有两个相同的玄学值则会有无限大的欧气加成。
  2. 同一个卡包如果有两个相邻的玄学值会有A点欧气加成。
  3. 相邻的两个卡包如果有相同的玄学值会有B点欧气加成。
  4. 相邻的两个卡包如果有相邻的玄学值会有C点欧气加成。
  5. 距离为2的卡包如果有相同玄学值会有D点欧气加成。
  6. 距离为2的卡包如果有相邻玄学值会有E点欧气加成。

以上的所有的加成是每存在一个符合条件就会加一次,,如卡包1,2,3的玄学值就会加两次。

但是,玄学值个不可控的东西,即使Yjq也只能自己决定(2,2),(2,3),(3,2),(3,3)这几包卡的玄学值。为了能够抽到更多的金色普通卡,, Yjq想知道自己能够获得的最多的欧气加成是多少。 注意你只能修改玄学值 ,不能修改玄学值的个数 。

【输入格式】

输入的第一行有 5个整数 A,B,C,D,E
接下去有6×6的代表初始玄学值。
每个玄学值为 [n:a1,a2,,an] 的描述形式。

【输出格式】

一行个整数代表答案。

【样例输入】

5 4 3 2 1
[1:1][2][3][4][5][6]
[1:1][2][3][4][5][6]
[1:1][2][5:1,2,3,4,5][5][6]
[1:1][ 1:2][5:1,2,3,4,5][5][6]
[1:1][2][3][4][5][6]
[1:1][2][3][4][5][6]

【样例输出】

250

【数据规模与约定】

对于100%的数据, 1A,B,C,D,E100,1n5,1ai30。有部分分。


solution

就是一个简单的九维dp而已

code

  • std by zhx
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<algorithm>

using namespace std;

#define now pre[a][b][c][d][e][s1][s2][s3][s4]
#define dis(a,b,c,d) (abs(a-c)+abs(b-d))

const int INF=0x3f3f3f3f;

int A,B,C,D,E,num[10][10],value[10][10][10],delta[10][10][40],dp[31][6][6][6][6][2][2][2][2];

char s[500];

bool map[6][6][6][6];

int main()
{
    freopen("c.in","r",stdin);
    freopen("c.out","w",stdout);

    scanf("%d%d%d%d%d",&A,&B,&C,&D,&E);
    for (int a=0;a<6;a++)
    {
        scanf("%s",s);
        int p=0;
        for (int b=0;b<6;b++)
        {
            int px=p;
            while (s[px]!=']')
                px++;
            p++;
            num[a][b]=s[p]-'0';
            p++;
            p++;
            for (int c=1;c<=num[a][b];c++)
            {
                int v=0;
                while (s[p]>='0' && s[p]<='9')
                {
                    v=v*10+s[p]-'0';
                    p++;
                }
                value[a][b][c]=v;
                p++;
            }
            p=px+1;
        }
    }
    int base=0;
    for (int a=0;a<6;a++)
        for (int b=0;b<6;b++)
            if (a>=2 && a<=3 && b>=2 && b<=3) ;
            else
            {
                sort(value[a][b]+1,value[a][b]+num[a][b]+1);
                for (int c=2;c<=num[a][b];c++)
                    if (value[a][b][c]-value[a][b][c-1]==1) base+=A;
                for (int c=2;c<=3;c++)
                    for (int d=2;d<=3;d++)
                    {
                        if (dis(a,b,c,d)==1)
                        {
                            for (int e=1;e<=num[a][b];e++)
                            {
                                delta[c][d][value[a][b][e]]+=B;
                                delta[c][d][value[a][b][e]-1]+=C;
                                delta[c][d][value[a][b][e]+1]+=C;
                            }
                        }
                        if (dis(a,b,c,d)==2)
                        {
                            for (int e=1;e<=num[a][b];e++)
                            {
                                delta[c][d][value[a][b][e]]+=D;
                                delta[c][d][value[a][b][e]-1]+=E;
                                delta[c][d][value[a][b][e]+1]+=E;
                            }
                        }
                    }
                for (int c=0;c<6;c++)
                    for (int d=0;d<6;d++)
                        if (dis(a,b,c,d)<=2 && (c!=a || d!=b) && !map[a][b][c][d])
                        {
                            map[a][b][c][d]=map[c][d][a][b]=true;
                            if (c>=2 && c<=3 && d>=2 && d<=3) ;
                            else
                            {
                                int dist=dis(a,b,c,d);
                                for (int e=1;e<=num[a][b];e++)
                                    for (int f=1;f<=num[c][d];f++)
                                    {
                                        if (abs(value[a][b][e]-value[c][d][f])==0)
                                        {
                                            if (dist==1) base+=B;
                                            else base+=D;
                                        }
                                        if (abs(value[a][b][e]-value[c][d][f])==1)
                                        {
                                            if (dist==1) base+=C;
                                            else base+=E;
                                        }
                                    }
                            }
                        }
            }
    memset(dp,0x3f,sizeof(dp));
    dp[0][0][0][0][0][0][0][0][0]=base;
    for (int a=0;a<30;a++)
        for (int b=0;b<=num[2][2];b++)
            for (int c=0;c<=num[2][3];c++)
                for (int d=0;d<=num[3][2];d++)
                    for (int e=0;e<=num[3][3];e++)
                        for (int s1=0;s1<=1;s1++)
                            for (int s2=0;s2<=1;s2++)
                                for (int s3=0;s3<=1;s3++)
                                    for (int s4=0;s4<=1;s4++)
                                        if (dp[a][b][c][d][e][s1][s2][s3][s4]!=INF)
                                        {
                                            int v=dp[a][b][c][d][e][s1][s2][s3][s4];
                                            for (int sx1=0;sx1<=(b!=num[2][2]);sx1++)
                                                for (int sx2=0;sx2<=(c!=num[2][3]);sx2++)
                                                    for (int sx3=0;sx3<=(d!=num[3][2]);sx3++)
                                                        for (int sx4=0;sx4<=(e!=num[3][3]);sx4++)
                                                        {
                                                            int wmt=0;
                                                            if (sx1) 
                                                            {
                                                                wmt+=delta[2][2][a+1];
                                                                if (s1) wmt+=A;
                                                                if (s2) wmt+=C;
                                                                if (s3) wmt+=C;
                                                                if (s4) wmt+=E;
                                                            }
                                                            if (sx2) 
                                                            {
                                                                wmt+=delta[2][3][a+1];
                                                                if (s1) wmt+=C;
                                                                if (s2) wmt+=A;
                                                                if (s3) wmt+=E;
                                                                if (s4) wmt+=C;
                                                            }
                                                            if (sx3) 
                                                            {
                                                                wmt+=delta[3][2][a+1];
                                                                if (s1) wmt+=C;
                                                                if (s2) wmt+=E;
                                                                if (s3) wmt+=A;
                                                                if (s4) wmt+=C;
                                                            }
                                                            if (sx4) 
                                                            {
                                                                wmt+=delta[3][3][a+1];
                                                                if (s1) wmt+=E;
                                                                if (s2) wmt+=C;
                                                                if (s3) wmt+=C;
                                                                if (s4) wmt+=A;
                                                            }
                                                            if (sx1 && sx2) wmt+=B;
                                                            if (sx1 && sx3) wmt+=B;
                                                            if (sx1 && sx4) wmt+=D;
                                                            if (sx2 && sx3) wmt+=D;
                                                            if (sx2 && sx4) wmt+=B;
                                                            if (sx3 && sx4) wmt+=B;
                                                            int &t=dp[a+1][b+sx1][c+sx2][d+sx3][e+sx4][sx1][sx2][sx3][sx4];
                                                            if (t>v+wmt) t=v+wmt;
                                                        }
                                        }
    int ans=INF;
    for (int a=0;a<=1;a++)
        for (int b=0;b<=1;b++)
            for (int c=0;c<=1;c++)
                for (int d=0;d<=1;d++)
                    ans=min(ans,dp[30][num[2][2]][num[2][3]][num[3][2]][num[3][3]][a][b][c][d]);
    printf("%d\n",ans);

    return 0;
}

除了T1都很可做的

%% 基础数据加载 node_coords = [ 120000 3900 1.2047e+04 3.9094e+03 1.2053e+04 3.9139e+03 1.2057e+04 3.9023e+03 1.2052e+04 3.8965e+03 1.2047e+04 3.9064e+03]; % 配送节点坐标 customer_data = xlsread('新建 Microsoft Excel 工作表.xlsx', 'Sheet1'); customer_coords = customer_data(:, 1:2); % 客户坐标 delivery_demand = customer_data(:,5); % 正向配送需求 recycle_demand = customer_data(:,6); % 逆向回收需求 node_types = [0, 1, 1, 1]; % 节点容量配置(特殊节点无限容量用Inf表示) node_capacities = [depot_capacity, depot_capacity, Inf, depot_capacity]; %% 参数设置 max_distance = 400; % 单程最大距离(km) vehicle_speed = 50; % 车速(km/h) vehicle_capacity = 10; % 单车运载量 depot_capacity = 10000; % 节点服务能力 operating_cost = 400; % 节点运营成本 cr1 = 300; % 车辆租赁成本 c0 = 200; % 车辆启动成本 c1 = 0.64; % 载重运输成本系数(元/吨·公里) c2 = 1.96; % 空车行驶成本系数(元/公里) %% 距离矩阵生成 all_points = [node_coords; customer_coords]; distance_matrix = squareform(pdist(all_points, 'euclidean')); %% 遗传算法参数 pop_size = 100; % 种群数量 max_gen = 50; % 最大迭代次数 cross_rate = 0.85; % 交叉概率 mutate_rate = 0.1; % 变异概率 %% 染色体编码函数 function chrom = createChrom(nodes_num, customers_num) allocation = randi(nodes_num, 1, customers_num); sequence = randperm(customers_num); chrom = [allocation, sequence]; end %% 适应度函数 function [total_cost] = fitnessFunc(chrom, distance_matrix, params) nodes_num = size(params.node_coords,1); customers_num = length(params.customer_coords); allocation = chrom(1:customers_num); sequence = chrom(customers_num+1:end); total_cost = 0; for n = 1:nodes_num node_customers = find(allocation == n); node_delivery = sum(params.delivery_demand(node_customers)); node_recycle = sum(params.recycle_demand(node_customers)); is_special_node = (params.node_types(n) == 0); % 特殊节点容量检查豁免 if ~is_special_node if node_delivery > params.node_capacities(n) total_cost = total_cost + 1e6; continue; end end % 节点容量检查 if node_delivery > params.depot_capacity total_cost = total_cost + 1e6; % 容量惩罚 continue; end % 路径规划 %% 修正后的路径规划逻辑 if ~isempty(node_customers) % 获取客户在全局路径序列中的位置 [~, seq_positions] = ismember(node_customers, sequence); % 组合过滤条件(同时处理0值和超限索引) valid_mask = (seq_positions <= length(sequence)); valid_positions = seq_positions(valid_mask); % 按染色体序列顺序重构路径 if ~isempty(valid_positions) % 按sequence中的原始顺序排序 [~, sort_idx] = sort(valid_positions); route_order = node_customers(valid_mask); route_order = route_order(sort_idx); % 保持染色体序列顺序 else route_order = []; end % 强化数据验证 if ~isempty(route_order) assert(all(ismember(route_order, sequence)),... '路径包含不存在于全局序列的客户: %s', mat2str(route_order)); assert(max(route_order) <= max(sequence),... '客户索引超限: %d > %d', max(route_order), max(sequence)); end i = 1; vehicle_count = 0; while i <= length(route_order) % 初始化当前路径段 segment = []; current_delivery = 0; current_recycle = 0; % 遍历客户构建可行路径段 for j = i:length(route_order) customer = route_order(j); % 检查新增客户是否超出容量 temp_delivery = current_delivery + params.delivery_demand(customer); temp_recycle = current_recycle + params.recycle_demand(customer); vehicle_routes = baseSplitRoutes(route_order, n, params, distance_matrix); if temp_delivery > params.vehicle_capacity || temp_recycle > params.vehicle_capacity % 超过容量时保留j之前的客户作为当前段 break; end if is_special_node vehicle_routes = specialSplitRoutes(route_order, n, params, distance_matrix); else vehicle_routes = baseSplitRoutes(route_order, n, params, distance_matrix); end % 更新当前段信息 segment = [segment, customer]; current_delivery = temp_delivery; current_recycle = temp_recycle; end % 处理有效路径段 if ~isempty(segment) vehicle_count = vehicle_count + 1; % 计算该段的运输成本(从仓库出发并返回) transport_cost = calculateSegmentCost(segment, n, params, distance_matrix); total_cost = total_cost + transport_cost; end % 移动索引到下一个未处理的客户 i = i + length(segment); % 处理单个客户超容的特殊情况 if isempty(segment) && i <= length(route_order) % 如果当前客户单独超容,跳过并施加惩罚 total_cost = total_cost + 1e6; i = i + 1; end end % 计算运输成本 if ~isempty(segment) vehicle_count = vehicle_count + 1; transport_cost = 0; % 配送中心到第一个客户 from = n; to = segment(1) + nodes_num; distance = distance_matrix(from, to); transport_cost = transport_cost + (params.c1*current_delivery + params.c2)*distance; % 客户间移动 for k = 2:length(segment) from = segment(k-1) + nodes_num; to = segment(k) + nodes_num; distance = distance_matrix(from, to); remaining_delivery = current_delivery - sum(params.delivery_demand(segment(1:k-1))); transport_cost = transport_cost + (params.c1*remaining_delivery + params.c2)*distance; end % 返回配送中心 from = segment(end) + nodes_num; to = n; distance = distance_matrix(from, to); transport_cost = transport_cost + (params.c1*current_recycle + params.c2)*distance; total_cost = total_cost + transport_cost; end end % 累加固定成本 total_cost = total_cost + params.operating_cost + vehicle_count*(params.cr1 + params.c0); end end figure('Name','适应度进化曲线','NumberTitle','off'); h_plot = plot(0, 0, 'b-', 0, 0, 'r--'); title('适应度进化过程'); xlabel('迭代代数'); ylabel('适应度值'); legend('最佳适应度', '平均适应度'); grid on; hold on; % 初始化存储数组 best_history = zeros(max_gen,1); avg_history = zeros(max_gen,1); %% 遗传算法主循环 population = arrayfun(@(x) createChrom(size(node_coords,1), size(customer_coords,1)),... 1:pop_size, 'UniformOutput', false); best_cost = Inf; adaptive_params = struct(... 'cross_rate', 0.85,... % 初始交叉率 'mutate_rate', 0.15,... % 初始变异率 'stagnation', 0); % 停滞计数器 for gen = 1:max_gen % 计算适应度 %% 修改后的适应度函数调用(添加max_distance字段) costs = cellfun(@(x) fitnessFunc(x, distance_matrix, struct(... 'node_coords', node_coords,... 'customer_coords', customer_coords,... 'delivery_demand', delivery_demand,... 'recycle_demand', recycle_demand,... 'depot_capacity', depot_capacity,... 'vehicle_capacity', vehicle_capacity,... 'max_distance', max_distance,... % 新增字段 'operating_cost', operating_cost,... 'cr1', cr1,... 'c0', c0,... 'c1', c1,... 'c2', c2)),... population); [min_cost, idx] = min(costs); current_avg = mean(costs); best_history(gen) = min_cost; avg_history(gen) = current_avg; % 更新可视化曲线 set(h_plot(1), 'XData', 1:gen, 'YData', best_history(1:gen)); set(h_plot(2), 'XData', 1:gen, 'YData', avg_history(1:gen)); xlim([1 max_gen]); drawnow; if min_cost < best_cost best_solution = population{idx}; best_cost = min_cost; end % 选择操作 selected_pop = tournamentSelection(population, costs, 3); % 交叉操作 %% 修正后的交叉操作部分 % 交叉操作 new_population = cell(1, pop_size); for i = 1:2:pop_size % 从selected_pop获取父代个体 parent1 = selected_pop{i}; parent2 = selected_pop{i+1}; if rand() < cross_rate [child1, child2] = depotCrossover(parent1, parent2, size(customer_coords,1)); new_population{i} = child1; new_population{i+1} = child2; else new_population{i} = parent1; new_population{i+1} = parent2; end end % 变异操作 for i = 1:pop_size if rand() < mutate_rate new_population{i} = depotMutate(new_population{i},... size(node_coords,1),... size(customer_coords,1)); end end if gen > 20 && std(costs) < 0.1*mean(costs) adaptive_params.cross_rate = min(0.95, adaptive_params.cross_rate + 0.05); adaptive_params.mutate_rate = min(0.3, adaptive_params.mutate_rate + 0.02); else adaptive_params.cross_rate = 0.85; adaptive_params.mutate_rate = 0.15; end % 使用调整后的参数 cross_rate = adaptive_params.cross_rate; mutate_rate = adaptive_params.mutate_rate; population = new_population; end %% 结果显示 disp(['最优成本:' num2str(best_cost)]); visualizeRoutes(best_solution, node_coords, customer_coords); %% 修正后的可视化函数(分拆为两个独立函数) function visualizeRoutes(chrom, depot_coords, customer_coords) % 整体路径可视化函数 num_customers = length(customer_coords); num_depots = size(depot_coords,1); figure; hold on; % 绘制仓库 scatter(depot_coords(:,1), depot_coords(:,2), 100, 'k^', 'filled'); % 绘制客户点 scatter(customer_coords(:,1), customer_coords(:,2), 50, 'bo'); % 解析路径 for d = 1:num_depots depot_customers = find(chrom(1:num_customers) == d); if ~isempty(depot_customers) [~, seq_pos] = ismember(depot_customers, chrom(num_customers+1:end)); valid_seq = seq_pos(seq_pos > 0); [~, order] = sort(valid_seq); sorted_customers = depot_customers(order); route = [depot_coords(d,:); customer_coords(sorted_customers,:); depot_coords(d,:)]; plot(route(:,1), route(:,2), 'LineWidth', 1.5); end end hold off; title('全局配送路径'); xlabel('X坐标'); ylabel('Y坐标'); legend('仓库', '客户点'); end function visualizeDepotRoutes(chrom, depot_coords, customer_coords) % 各节点独立路径可视化函数 num_customers = length(customer_coords); num_depots = size(depot_coords,1); for d = 1:num_depots figure('Position', [200+(d-1)*50, 200+(d-1)*50, 600, 400]); hold on; title(['配送中心' num2str(d) '路径规划']); % 绘制当前配送中心 scatter(depot_coords(d,1), depot_coords(d,2), 150, 'r^', 'filled'); depot_customers = find(chrom(1:num_customers) == d); if ~isempty(depot_customers) [~, seq_pos] = ismember(depot_customers, chrom(num_customers+1:end)); valid_seq = seq_pos(seq_pos > 0 & seq_pos <= length(chrom)-num_customers); [~, order] = sort(valid_seq); sorted_customers = depot_customers(order); % 客户点标注 scatter(customer_coords(sorted_customers,1),... customer_coords(sorted_customers,2),... 80, 'bo', 'filled'); text_offset = 0.1 * max(range(customer_coords)); text(customer_coords(sorted_customers,1)+text_offset,... customer_coords(sorted_customers,2)+text_offset,... cellstr(num2str(sorted_customers')),... 'FontSize',8); % 路径绘制 route = [depot_coords(d,:); customer_coords(sorted_customers,:); depot_coords(d,:)]; plot(route(:,1), route(:,2), 'b--o',... 'LineWidth',1.5,... 'MarkerSize',6,... 'MarkerFaceColor','w'); else text(mean(depot_coords(d,1)), mean(depot_coords(d,2)),... '无服务客户',... 'HorizontalAlignment','center',... 'FontSize',12); end xlabel('X坐标 (米)'); ylabel('Y坐标 (米)'); grid on; axis equal; hold off; end end %% 交叉操作函数实现 function [child1, child2] = depotCrossover(parent1, parent2, num_customers) % 分配部分交叉(均匀交叉) alloc_part1 = parent1(1:num_customers); alloc_part2 = parent2(1:num_customers); mask = randi([0 1], 1, num_customers); child1_alloc = alloc_part1.*mask + alloc_part2.*(~mask); child2_alloc = alloc_part1.*(~mask) + alloc_part2.*mask; % 路径顺序交叉(OX交叉) seq_part1 = parent1(num_customers+1:end); seq_part2 = parent2(num_customers+1:end); [child1_seq, child2_seq] = oxCrossover(seq_part1, seq_part2); child1 = [child1_alloc, child1_seq]; child2 = [child2_alloc, child2_seq]; end %% 修正后的OX交叉辅助函数 function [child1, child2] = oxCrossover(parent1, parent2) n = length(parent1); cp = sort(randi(n-1,1,2)); % 确保交叉点有效 if cp(1) == cp(2), cp(2) = cp(2)+1; end % 防止相同切点 % 子代1生成 segment = parent1(cp(1):cp(2)); remaining = parent2(~ismember(parent2, segment)); child1 = [remaining(1:cp(1)-1), segment, remaining(cp(1):end)]; % 子代2生成(修正索引错误) segment = parent2(cp(1):cp(2)); remaining = parent1(~ismember(parent1, segment)); % 确保索引不越界 if (cp(1)-1) <= length(remaining) part1 = remaining(1:cp(1)-1); else part1 = remaining(1:end); end child2 = [part1, segment, remaining(cp(1):end)]; end %% 变异操作函数实现 function mutated = depotMutate(chrom, num_depots, num_customers) if rand() < 0.5 % 分配变异:随机改变一个客户的分配 pos = randi(num_customers); new_depot = randi(num_depots); mutated = chrom; mutated(pos) = new_depot; else % 路径顺序变异:交换两个位置 seq = chrom(num_customers+1:end); swap_pos = randperm(num_customers, 2); seq(swap_pos) = seq(fliplr(swap_pos)); mutated = [chrom(1:num_customers), seq]; end end %% 历史最优成本可视化 % 生成累积最优成本数组 cumulative_min = cummin(best_history); figure('Color','w'); plot(cumulative_min, 'b-o',... 'LineWidth',1.2,... 'MarkerSize',4,... 'MarkerFaceColor','w'); % 设置坐标轴标签 xlabel('迭代代数'); ylabel('历史最优成本 (元)'); title('全局最优成本进化过程'); % 自动标注最终最优值 [final_min, final_gen] = min(cumulative_min); text(final_gen, final_min,... sprintf(' %.2f万 @%d代', final_min/10000, final_gen),... 'VerticalAlignment','bottom',... 'FontSize',9); % 智能坐标轴设置 ax = gca; ax.YAxis.Exponent = floor(log10(final_min)) - 1; % 自动确定指数 grid on; %% 新增的运输成本计算函数 function cost = calculateRouteCost(route, params, distance_matrix) num_nodes = size(params.node_coords,1); depot_id = mode(params.chrom(route)); % 获取所属配送中心 % 正向运输成本 forward_cost = 0; current_load = sum(params.delivery_demand(route)); % 配送中心到第一个客户 from = depot_id; to = route(1) + num_nodes; distance = distance_matrix(from, to); forward_cost = forward_cost + (params.c1*current_load + params.c2)*distance; % 客户间运输 for k = 2:length(route) from = route(k-1) + num_nodes; to = route(k) + num_nodes; distance = distance_matrix(from, to); current_load = current_load - params.delivery_demand(route(k-1)); forward_cost = forward_cost + (params.c1*current_load + params.c2)*distance; end % 逆向运输成本 recycle_load = sum(params.recycle_demand(route)); from = route(end) + num_nodes; to = depot_id; distance = distance_matrix(from, to); recycle_cost = (params.c1*recycle_load + params.c2)*distance; cost = forward_cost + recycle_cost; end %% 配送方案输出函数 function printDeliveryPlan(best_solution, params, distance_matrix) num_depots = size(params.node_coords,1); num_customers = size(params.customer_coords,1); % 解析染色体 allocation = best_solution(1:num_customers); global_sequence = best_solution(num_customers+1:end); % 创建结果结构体 depot_info = struct(... 'DepotID', {},... 'Vehicles', {},... 'TotalCost', {},... 'Details', {}); % 遍历所有配送中心 for depot_id = 1:num_depots % 获取当前配送中心分配的客户 customers = find(allocation == depot_id); if isempty(customers) continue; end % 获取路径顺序 [~, seq_pos] = ismember(customers, global_sequence); valid_seq = seq_pos(seq_pos > 0); [~, sort_idx] = sort(valid_seq); route_order = customers(sort_idx); % 路径分割 vehicle_routes = baseSplitRoutes(route_order, depot_id, params, distance_matrix); % 计算成本和详细信息 depot_cost = 0; vehicle_details = cell(length(vehicle_routes),1); for v = 1:length(vehicle_routes) route = vehicle_routes{v}; [cost, detail] = calculateVehicleCost(route, depot_id, params, distance_matrix); vehicle_details{v} = detail; depot_cost = depot_cost + cost; end % 添加固定成本 depot_cost = depot_cost + params.operating_cost + ... length(vehicle_routes)*(params.cr1 + params.c0); % 存储结果 depot_info(end+1) = struct(... 'DepotID', depot_id,... 'Vehicles', length(vehicle_routes),... 'TotalCost', depot_cost,... 'Details', {vehicle_details}); end %% 打印结果 fprintf('========== 全局配送方案 ==========\n'); total_cost = sum([depot_info.TotalCost]); fprintf('总运营成本: %.2f 万元\n', total_cost/10000); for d = 1:length(depot_info) fprintf('\n=== 配送中心%d ===\n', depot_info(d).DepotID); fprintf('派出车辆: %d\n', depot_info(d).Vehicles); fprintf('中心总成本: %.2f 万元\n', depot_info(d).TotalCost/10000); % 打印车辆明细 fprintf('\n车辆明细:\n'); fprintf('%-8s%-12s%-12s%-10s%-10s%-12s%-15s\n',... '车辆ID','正向载货量','逆向载载量','里程(km)','运输成本','总成本','服务客户顺序'); for v = 1:length(depot_info(d).Details) detail = depot_info(d).Details{v}; total = detail.transport_cost + params.cr1 + params.c0; % 生成客户顺序字符串 customer_str = strjoin(arrayfun(@(x) sprintf('%d',x), detail.customers, 'UniformOutput', false),'->'); fprintf('%-8d%-12.2f%-12.2f%-10.2f%-10.2f%-12.2f%-15s\n',... v,... detail.delivery_load,... detail.recycle_load,... detail.distance,... detail.transport_cost,... total,... customer_str); % 新增客户顺序输出 end end end %% 非递归路径分割函数 function vehicle_routes = baseSplitRoutes(route_order, depot_id, params, distance_matrix) vehicle_routes = {}; num_nodes = size(params.node_coords,1); i = 1; % 预计算所有客户到仓库的距离 depot_distances = distance_matrix(depot_id, num_nodes+1:end); while i <= length(route_order) current_load = 0; current_distance = 0; segment = []; % 初始仓库到第一个客户的检查 first_cust = route_order(i); start_distance = depot_distances(first_cust); return_distance = distance_matrix(num_nodes+first_cust, depot_id); for j = i:length(route_order) cust = route_order(j); % 新增客户后的载重检查 new_load = current_load + params.delivery_demand(cust) + params.recycle_demand(cust); % 计算新增客户后的总距离 if isempty(segment) new_dist = start_distance + return_distance; else last_cust = segment(end); leg1 = distance_matrix(num_nodes+last_cust, num_nodes+cust); leg2 = distance_matrix(num_nodes+cust, depot_id); new_dist = current_distance - distance_matrix(num_nodes+last_cust, depot_id)... + leg1 + leg2; end % 约束条件验证 if new_load > params.vehicle_capacity || new_dist > params.max_distance break; end % 更新当前路径段 segment = [segment, cust]; current_load = new_load; current_distance = new_dist; end if ~isempty(segment) vehicle_routes{end+1} = segment; i = i + length(segment); else % 处理无法服务的客户 warning('客户%d无法满足约束条件', route_order(i)); i = i + 1; end end end %% 修正后的车辆成本计算函数 function [total_cost, detail] = calculateVehicleCost(route, depot_id, params, distance_matrix) num_nodes = size(params.node_coords,1); % 运输成本计算 transport_cost = 0; total_distance = 0; % 仓库到第一个客户 from = depot_id; to = route(1) + num_nodes; distance = distance_matrix(from, to); transport_cost = transport_cost + (params.c1*sum(params.delivery_demand(route)) + params.c2)*distance; total_distance = total_distance + distance; % 客户间移动 for k = 2:length(route) from = route(k-1) + num_nodes; to = route(k) + num_nodes; distance = distance_matrix(from, to); remaining_delivery = sum(params.delivery_demand(route(k:end))); transport_cost = transport_cost + (params.c1*remaining_delivery + params.c2)*distance; total_distance = total_distance + distance; end % 返回仓库 from = route(end) + num_nodes; to = depot_id; distance = distance_matrix(from, to); transport_cost = transport_cost + (params.c1*sum(params.recycle_demand(route)) + params.c2)*distance; total_distance = total_distance + distance; % 修正后的结构体定义(合并字段定义) detail = struct(... 'customers', route,... % 客户顺序 'delivery_load', sum(params.delivery_demand(route)),... 'recycle_load', sum(params.recycle_demand(route)),... 'distance', total_distance,... 'transport_cost',transport_cost); total_cost = transport_cost + params.cr1 + params.c0; end %% 在主循环后调用输出函数(添加在结果显示部分) % 结果显示 disp(['最优成本:' num2str(best_cost)]); visualizeRoutes(best_solution, node_coords, customer_coords); visualizeDepotRoutes(best_solution, node_coords, customer_coords); % 分节点视图 %% 修改后的printDeliveryPlan调用 printDeliveryPlan(best_solution, struct(... 'node_coords', node_coords,... 'customer_coords', customer_coords,... 'delivery_demand', delivery_demand,... 'recycle_demand', recycle_demand,... 'depot_capacity', depot_capacity,... 'vehicle_capacity', vehicle_capacity,... 'max_distance', max_distance,... % 新增字段 'operating_cost', operating_cost,... 'cr1', cr1,... 'c0', c0,... 'c1', c1,... 'c2', c2), distance_matrix); function optimized_route = twoOptOptimization(route, distance_matrix, params) num_nodes = length(route); improved = true; best_route = route; best_cost = calculateRouteCost(route, params, distance_matrix); while improved improved = false; for i = 1:num_nodes-1 for j = i+2:num_nodes new_route = best_route; new_route(i+1:j) = new_route(j:-1:i+1); new_cost = calculateRouteCost(new_route, params, distance_matrix); if new_cost < best_cost best_route = new_route; best_cost = new_cost; improved = true; end end end end optimized_route = best_route; end function selected = tournamentSelection(population, fitness, tournament_size) pop_size = length(population); selected = cell(1, pop_size); for i = 1:pop_size candidates = randperm(pop_size, tournament_size); [~, idx] = min(fitness(candidates)); selected{i} = population{candidates(idx)}; end end function vehicle_routes = optimizedSplitRoutes(route_order, depot_id, params, distance_matrix) % 调用基础分割函数 raw_routes = baseSplitRoutes(route_order, depot_id, params, distance_matrix); % 对每个路径段进行2-opt优化 optimized_routes = cell(size(raw_routes)); for i = 1:length(raw_routes) optimized_routes{i} = twoOptOptimization(raw_routes{i}, distance_matrix, params); end end function transport_cost = calculateSegmentCost(segment, depot_id, params, distance_matrix) num_nodes = size(params.node_coords,1); transport_cost = 0; % 正向运输成本 current_delivery = sum(params.delivery_demand(segment)); % 配送中心到第一个客户 from = depot_id; to = segment(1) + num_nodes; distance = distance_matrix(from, to); transport_cost = transport_cost + (params.c1*current_delivery + params.c2)*distance; % 客户间运输 for k = 2:length(segment) from = segment(k-1) + num_nodes; to = segment(k) + num_nodes; distance = distance_matrix(from, to); remaining_delivery = current_delivery - sum(params.delivery_demand(segment(1:k-1))); transport_cost = transport_cost + (params.c1*remaining_delivery + params.c2)*distance; end % 逆向运输成本 recycle_load = sum(params.recycle_demand(segment)); from = segment(end) + num_nodes; to = depot_id; distance = distance_matrix(from, to); transport_cost = transport_cost + (params.c1*recycle_load + params.c2)*distance; end我都没有这段
05-30
%% 基础数据加载 node_coords = [ 12039.846772,3908.892133 12051.704390,3899.422153 12038.547752,3904.837542 ]; % 配送节点坐标 customer_data = xlsread('新建 Microsoft Excel 工作表.xlsx', 'Sheet1'); customer_coords = customer_data(:, 1:2); % 客户坐标 delivery_demand = customer_data(:,3); % 正向配送需求 recycle_demand = customer_data(:,4); % 逆向回收需求 %% 参数设置 max_distance = 400; % 单程最大距离(km) vehicle_speed = 50; % 车速(km/h) vehicle_capacity = 10; % 单车运载量 depot_capacity = 10000; % 节点服务能力 operating_cost = 400; % 节点运营成本 cr1 = 300; % 车辆租赁成本 c0 = 200; % 车辆启动成本 c1 = 0.64; % 载重运输成本系数(元/吨·公里) c2 = 1.96; % 空车行驶成本系数(元/公里) %% 距离矩阵生成 all_points = [node_coords; customer_coords]; distance_matrix = squareform(pdist(all_points, 'euclidean')); %% 遗传算法参数 pop_size = 100; % 种群数量 max_gen = 200; % 最大迭代次数 cross_rate = 0.85; % 交叉概率 adaptive_params = struct(... 'init_mutate', 0.15,... 'max_mutate', 0.3,... 'destroy_prob', 0.7); % 变异概率 %% 染色体编码函数 function chrom = validateChromosome(chrom, num_depots, num_customers) % 检查分配部分合法性 chrom(1:num_customers) = max(1, min(num_depots, chrom(1:num_customers))); % 检查路径部分唯一性 path_part = chrom(num_customers+1:end); if length(unique(path_part)) ~= num_customers chrom(num_customers+1:end) = randperm(num_customers); end end %% 适应度函数 function [total_cost] = fitnessFunc(chrom, distance_matrix, params) nodes_num = size(params.node_coords,1); customers_num = length(params.customer_coords); allocation = chrom(1:customers_num); sequence = chrom(customers_num+1:end); total_cost = 0; for n = 1:nodes_num node_customers = find(allocation == n); node_delivery = sum(params.delivery_demand(node_customers)); node_recycle = sum(params.recycle_demand(node_customers)); % 节点容量检查 if node_delivery > params.depot_capacity total_cost = total_cost + 1e6; % 容量惩罚 continue; end % 路径规划 %% 修正后的路径规划逻辑 if ~isempty(node_customers) % 获取客户在全局路径序列中的位置 [~, seq_positions] = ismember(node_customers, sequence); % 组合过滤条件(同时处理0值和超限索引) valid_mask = (seq_positions <= length(sequence)); valid_positions = seq_positions(valid_mask); % 按染色体序列顺序重构路径 if ~isempty(valid_positions) % 按sequence中的原始顺序排序 [~, sort_idx] = sort(valid_positions); route_order = node_customers(valid_mask); route_order = route_order(sort_idx); % 保持染色体序列顺序 else route_order = []; end % 强化数据验证 if ~isempty(route_order) assert(all(ismember(route_order, sequence)),... '路径包含不存在于全局序列的客户: %s', mat2str(route_order)); assert(max(route_order) <= max(sequence),... '客户索引超限: %d > %d', max(route_order), max(sequence)); end i = 1; vehicle_count = 0; while i <= length(route_order) % 初始化当前路径段 segment = []; current_delivery = 0; current_recycle = 0; % 遍历客户构建可行路径段 for j = i:length(route_order) customer = route_order(j); % 检查新增客户是否超出容量 temp_delivery = current_delivery + params.delivery_demand(customer); temp_recycle = current_recycle + params.recycle_demand(customer); vehicle_routes = baseSplitRoutes(route_order, n, params, distance_matrix); if temp_delivery > params.vehicle_capacity || temp_recycle > params.vehicle_capacity % 超过容量时保留j之前的客户作为当前段 break; end % 更新当前段信息 segment = [segment, customer]; current_delivery = temp_delivery; current_recycle = temp_recycle; end % 处理有效路径段 if ~isempty(segment) vehicle_count = vehicle_count + 1; % 计算该段的运输成本(从仓库出发并返回) transport_cost = calculateSegmentCost(segment, n, params, distance_matrix); total_cost = total_cost + transport_cost; end % 移动索引到下一个未处理的客户 i = i + length(segment); % 处理单个客户超容的特殊情况 if isempty(segment) && i <= length(route_order) % 如果当前客户单独超容,跳过并施加惩罚 total_cost = total_cost + 1e6; i = i + 1; end end [node_cost, vehicles] = calculateNodeCost(route_order, n, params, distance_matrix); % 计算运输成本 if ~isempty(segment) vehicle_count = vehicle_count + 1; transport_cost = 0; % 配送中心到第一个客户 from = n; to = segment(1) + nodes_num; distance = distance_matrix(from, to); transport_cost = transport_cost + (params.c1*current_delivery + params.c2)*distance; % 客户间移动 for k = 2:length(segment) from = segment(k-1) + nodes_num; to = segment(k) + nodes_num; distance = distance_matrix(from, to); remaining_delivery = current_delivery - sum(params.delivery_demand(segment(1:k-1))); transport_cost = transport_cost + (params.c1*remaining_delivery + params.c2)*distance; end % 返回配送中心 from = segment(end) + nodes_num; to = n; distance = distance_matrix(from, to); transport_cost = transport_cost + (params.c1*current_recycle + params.c2)*distance; total_cost = total_cost + node_cost + params.operating_cost; end end % 累加固定成本 total_cost = total_cost + params.operating_cost + vehicle_count*(params.cr1 + params.c0); end end figure('Name','适应度进化曲线','NumberTitle','off'); h_plot = plot(0, 0, 'b-', 0, 0, 'r--'); title('适应度进化过程'); xlabel('迭代代数'); ylabel('适应度值'); legend('最佳适应度', '平均适应度'); grid on; hold on; mutation_stats = zeros(max_gen,3); % [总变异次数, 破坏性变异, 微调变异] % 初始化存储数组 best_history = zeros(max_gen,1); avg_history = zeros(max_gen,1); %% 遗传算法主循环 population = arrayfun(@(x) createChrom(size(node_coords,1), size(customer_coords,1)),... 1:pop_size, 'UniformOutput', false); best_cost = Inf; adaptive_params = struct(... 'cross_rate', 0.85,... % 初始交叉率 'mutate_rate', 0.15,... % 初始变异率 'stagnation', 0); % 停滞计数器 for gen = 1:max_gen % 计算适应度 %% 修改后的适应度函数调用(添加max_distance字段) costs = cellfun(@(x) fitnessFunc(x, distance_matrix, struct(... 'node_coords', node_coords,... 'customer_coords', customer_coords,... 'delivery_demand', delivery_demand,... 'recycle_demand', recycle_demand,... 'depot_capacity', depot_capacity,... 'vehicle_capacity', vehicle_capacity,... 'max_distance', max_distance,... % 新增字段 'operating_cost', operating_cost,... 'cr1', cr1,... 'c0', c0,... 'c1', c1,... 'c2', c2)),... population); [min_cost, idx] = min(costs); current_avg = mean(costs); best_history(gen) = min_cost; avg_history(gen) = current_avg; % 更新可视化曲线 set(h_plot(1), 'XData', 1:gen, 'YData', best_history(1:gen)); set(h_plot(2), 'XData', 1:gen, 'YData', avg_history(1:gen)); xlim([1 max_gen]); drawnow; if min_cost < best_cost best_solution = population{idx}; best_cost = min_cost; end % 选择操作 selected_pop = tournamentSelection(population, costs, 3); % 交叉操作 %% 修正后的交叉操作部分 % 交叉操作 new_population = cell(1, pop_size); for i = 1:2:pop_size % 从selected_pop获取父代个体 parent1 = selected_pop{i}; parent2 = selected_pop{i+1}; if rand() < cross_rate [child1, child2] = depotCrossover(parent1, parent2, size(customer_coords,1)); new_population{i} = child1; new_population{i+1} = child2; else new_population{i} = parent1; new_population{i+1} = parent2; end end % 变异操作 for i = 1:pop_size new_population{i} = adaptiveMutation(... new_population{i},... % 当前个体 gen, max_gen,... % 当前代数/最大代数 size(node_coords,1),... % 配送中心数量 size(customer_coords,1)... % 客户数量 ); end if gen > 20 && std(costs) < 0.1*mean(costs) adaptive_params.cross_rate = min(0.95, adaptive_params.cross_rate + 0.05); adaptive_params.mutate_rate = min(0.3, adaptive_params.mutate_rate + 0.02); else adaptive_params.cross_rate = 0.85; adaptive_params.mutate_rate = 0.15; end % 使用调整后的参数 cross_rate = adaptive_params.cross_rate; mutate_rate = adaptive_params.mutate_rate; population = new_population; end %% 结果显示 disp(['最优成本:' num2str(best_cost)]); visualizeRoutes(best_solution, node_coords, customer_coords); %% 修正后的可视化函数(分拆为两个独立函数) function visualizeRoutes(chrom, depot_coords, customer_coords) % 整体路径可视化函数 num_customers = length(customer_coords); num_depots = size(depot_coords,1); figure; hold on; % 绘制仓库 scatter(depot_coords(:,1), depot_coords(:,2), 100, 'k^', 'filled'); % 绘制客户点 scatter(customer_coords(:,1), customer_coords(:,2), 50, 'bo'); % 解析路径 for d = 1:num_depots depot_customers = find(chrom(1:num_customers) == d); if ~isempty(depot_customers) [~, seq_pos] = ismember(depot_customers, chrom(num_customers+1:end)); valid_seq = seq_pos(seq_pos > 0); [~, order] = sort(valid_seq); sorted_customers = depot_customers(order); route = [depot_coords(d,:); customer_coords(sorted_customers,:); depot_coords(d,:)]; plot(route(:,1), route(:,2), 'LineWidth', 1.5); end end hold off; title('全局配送路径'); xlabel('X坐标'); ylabel('Y坐标'); legend('仓库', '客户点'); end function visualizeDepotRoutes(chrom, depot_coords, customer_coords) % 各节点独立路径可视化函数 num_customers = length(customer_coords); num_depots = size(depot_coords,1); for d = 1:num_depots figure('Position', [200+(d-1)*50, 200+(d-1)*50, 600, 400]); hold on; title(['配送中心' num2str(d) '路径规划']); % 绘制当前配送中心 scatter(depot_coords(d,1), depot_coords(d,2), 150, 'r^', 'filled'); depot_customers = find(chrom(1:num_customers) == d); if ~isempty(depot_customers) [~, seq_pos] = ismember(depot_customers, chrom(num_customers+1:end)); valid_seq = seq_pos(seq_pos > 0 & seq_pos <= length(chrom)-num_customers); [~, order] = sort(valid_seq); sorted_customers = depot_customers(order); % 客户点标注 scatter(customer_coords(sorted_customers,1),... customer_coords(sorted_customers,2),... 80, 'bo', 'filled'); text_offset = 0.1 * max(range(customer_coords)); text(customer_coords(sorted_customers,1)+text_offset,... customer_coords(sorted_customers,2)+text_offset,... cellstr(num2str(sorted_customers')),... 'FontSize',8); % 路径绘制 route = [depot_coords(d,:); customer_coords(sorted_customers,:); depot_coords(d,:)]; plot(route(:,1), route(:,2), 'b--o',... 'LineWidth',1.5,... 'MarkerSize',6,... 'MarkerFaceColor','w'); else text(mean(depot_coords(d,1)), mean(depot_coords(d,2)),... '无服务客户',... 'HorizontalAlignment','center',... 'FontSize',12); end xlabel('X坐标 (米)'); ylabel('Y坐标 (米)'); grid on; axis equal; hold off; end end %% 交叉操作函数实现 function [child1, child2] = depotCrossover(parent1, parent2, num_customers) % 分配部分交叉(均匀交叉) alloc_part1 = parent1(1:num_customers); alloc_part2 = parent2(1:num_customers); mask = randi([0 1], 1, num_customers); child1_alloc = alloc_part1.*mask + alloc_part2.*(~mask); child2_alloc = alloc_part1.*(~mask) + alloc_part2.*mask; % 路径顺序交叉(OX交叉) seq_part1 = parent1(num_customers+1:end); seq_part2 = parent2(num_customers+1:end); [child1_seq, child2_seq] = oxCrossover(seq_part1, seq_part2); child1 = [child1_alloc, child1_seq]; child2 = [child2_alloc, child2_seq]; end %% 修正后的OX交叉辅助函数 function [child1, child2] = oxCrossover(parent1, parent2) n = length(parent1); cp = sort(randi(n-1,1,2)); % 确保交叉点有效 if cp(1) == cp(2), cp(2) = cp(2)+1; end % 防止相同切点 % 子代1生成 segment = parent1(cp(1):cp(2)); remaining = parent2(~ismember(parent2, segment)); child1 = [remaining(1:cp(1)-1), segment, remaining(cp(1):end)]; % 子代2生成(修正索引错误) segment = parent2(cp(1):cp(2)); remaining = parent1(~ismember(parent1, segment)); % 确保索引不越界 if (cp(1)-1) <= length(remaining) part1 = remaining(1:cp(1)-1); else part1 = remaining(1:end); end child2 = [part1, segment, remaining(cp(1):end)]; end %% 变异操作函数实现 function mutated = adaptiveMutation(chrom, current_gen, max_gen, num_depots, num_customers) % 动态调整基础变异率(0.1 → 0.3) global mutation_stats; if nargin == 0 % 仅用于统计 return end base_rate = 0.1 + 0.2*(current_gen/max_gen); if rand() < base_rate % 70%概率执行破坏性变异 if rand() < 0.7 % 变异类型1:改变3个客户的分配 mutate_pos = randperm(num_customers, 3); new_depots = randi(num_depots, 1, 3); mutated = chrom; mutated(mutate_pos) = new_depots; % 变异类型2:路径段反转(长度5的随机段) start_pos = randi(num_customers-4); end_pos = start_pos+4; mutated(num_customers+start_pos:num_customers+end_pos) = ... fliplr(mutated(num_customers+start_pos:num_customers+end_pos)); else % 30%概率执行微调变异 swap_pos = randperm(num_customers, 2); mutated = chrom; % 交换路径顺序中的两个位置 temp = mutated(num_customers+swap_pos(1)); mutated(num_customers+swap_pos(1)) = mutated(num_customers+swap_pos(2)); mutated(num_customers+swap_pos(2)) = temp; if rand() < base_rate if rand() < 0.7 mutation_stats(gen,2) = mutation_stats(gen,2) + 1; else mutation_stats(gen,3) = mutation_stats(gen,3) + 1; end mutation_stats(gen,1) = mutation_stats(gen,1) + 1; end end else mutated = chrom; % 保持原染色体 end % 添加染色体合法性检查 mutated = validateChromosome(mutated, num_depots, num_customers); end %% 历史最优成本可视化 % 生成累积最优成本数组 cumulative_min = cummin(best_history); figure('Color','w'); plot(cumulative_min, 'b-o',... 'LineWidth',1.2,... 'MarkerSize',4,... 'MarkerFaceColor','w'); % 设置坐标轴标签 xlabel('迭代代数'); ylabel('历史最优成本 (元)'); title('全局最优成本进化过程'); % 自动标注最终最优值 [final_min, final_gen] = min(cumulative_min); text(final_gen, final_min,... sprintf(' %.2f万 @%d代', final_min/10000, final_gen),... 'VerticalAlignment','bottom',... 'FontSize',9); % 智能坐标轴设置 ax = gca; ax.YAxis.Exponent = floor(log10(final_min)) - 1; % 自动确定指数 grid on; %% 新增的运输成本计算函数 function cost = calculateRouteCost(route, params, distance_matrix) num_nodes = size(params.node_coords,1); depot_id = mode(params.chrom(route)); % 获取所属配送中心 % 正向运输成本 forward_cost = 0; current_load = sum(params.delivery_demand(route)); % 配送中心到第一个客户 from = depot_id; to = route(1) + num_nodes; distance = distance_matrix(from, to); forward_cost = forward_cost + (params.c1*current_load + params.c2)*distance; % 客户间运输 for k = 2:length(route) from = route(k-1) + num_nodes; to = route(k) + num_nodes; distance = distance_matrix(from, to); current_load = current_load - params.delivery_demand(route(k-1)); forward_cost = forward_cost + (params.c1*current_load + params.c2)*distance; end % 逆向运输成本 recycle_load = sum(params.recycle_demand(route)); from = route(end) + num_nodes; to = depot_id; distance = distance_matrix(from, to); recycle_cost = (params.c1*recycle_load + params.c2)*distance; cost = forward_cost + recycle_cost; end %% 配送方案输出函数 function printDeliveryPlan(best_solution, params, distance_matrix) num_depots = size(params.node_coords,1); num_customers = size(params.customer_coords,1); % 解析染色体 allocation = best_solution(1:num_customers); global_sequence = best_solution(num_customers+1:end); % 创建结果结构体 depot_info = struct(... 'DepotID', {},... 'Vehicles', {},... 'TotalCost', {},... 'Details', {}); % 遍历所有配送中心 for depot_id = 1:num_depots % 获取当前配送中心分配的客户 customers = find(allocation == depot_id); if isempty(customers) continue; end % 获取路径顺序 [~, seq_pos] = ismember(customers, global_sequence); valid_seq = seq_pos(seq_pos > 0); [~, sort_idx] = sort(valid_seq); route_order = customers(sort_idx); % 路径分割 vehicle_routes = baseSplitRoutes(route_order, depot_id, params, distance_matrix); % 计算成本和详细信息 depot_cost = 0; vehicle_details = cell(length(vehicle_routes),1); for v = 1:length(vehicle_routes) route = vehicle_routes{v}; [cost, detail] = calculateVehicleCost(route, depot_id, params, distance_matrix); vehicle_details{v} = detail; depot_cost = depot_cost + cost; end % 添加固定成本 depot_cost = depot_cost + params.operating_cost + ... length(vehicle_routes)*(params.cr1 + params.c0); % 存储结果 depot_info(end+1) = struct(... 'DepotID', depot_id,... 'Vehicles', length(vehicle_routes),... 'TotalCost', depot_cost,... 'Details', {vehicle_details}); end %% 打印结果 fprintf('========== 全局配送方案 ==========\n'); total_cost = sum([depot_info.TotalCost]); fprintf('总运营成本: %.2f 万元\n', total_cost/10000); for d = 1:length(depot_info) fprintf('\n=== 配送中心%d ===\n', depot_info(d).DepotID); fprintf('派出车辆: %d\n', depot_info(d).Vehicles); fprintf('中心总成本: %.2f 万元\n', depot_info(d).TotalCost/10000); % 打印车辆明细 fprintf('\n车辆明细:\n'); fprintf('%-8s%-12s%-12s%-10s%-10s%-12s%-15s\n',... '车辆ID','正向载货量','逆向载载量','里程(km)','运输成本','总成本','服务客户顺序'); for v = 1:length(depot_info(d).Details) detail = depot_info(d).Details{v}; total = detail.transport_cost + params.cr1 + params.c0; % 生成客户顺序字符串 customer_str = strjoin(arrayfun(@(x) sprintf('%d',x), detail.customers, 'UniformOutput', false),'->'); fprintf('%-8d%-12.2f%-12.2f%-10.2f%-10.2f%-12.2f%-15s\n',... v,... detail.delivery_load,... detail.recycle_load,... detail.distance,... detail.transport_cost,... total,... customer_str); % 新增客户顺序输出 end end end %% 非递归路径分割函数 function vehicle_routes = baseSplitRoutes(route_order, depot_id, params, distance_matrix) vehicle_routes = {}; num_nodes = size(params.node_coords,1); i = 1; % 预计算所有客户到仓库的距离 depot_distances = distance_matrix(depot_id, num_nodes+1:end); while i <= length(route_order) current_load = 0; current_distance = 0; segment = []; % 初始仓库到第一个客户的检查 first_cust = route_order(i); start_distance = depot_distances(first_cust); return_distance = distance_matrix(num_nodes+first_cust, depot_id); for j = i:length(route_order) cust = route_order(j); % 新增客户后的载重检查 new_load = current_load + params.delivery_demand(cust) + params.recycle_demand(cust); % 计算新增客户后的总距离 if isempty(segment) new_dist = start_distance + return_distance; else last_cust = segment(end); leg1 = distance_matrix(num_nodes+last_cust, num_nodes+cust); leg2 = distance_matrix(num_nodes+cust, depot_id); new_dist = current_distance - distance_matrix(num_nodes+last_cust, depot_id)... + leg1 + leg2; end % 约束条件验证 if new_load > params.vehicle_capacity || new_dist > params.max_distance break; end % 更新当前路径段 segment = [segment, cust]; current_load = new_load; current_distance = new_dist; end if ~isempty(segment) vehicle_routes{end+1} = segment; i = i + length(segment); else % 处理无法服务的客户 warning('客户%d无法满足约束条件', route_order(i)); i = i + 1; end end end %% 修正后的车辆成本计算函数 function [total_cost, detail] = calculateVehicleCost(route, depot_id, params, distance_matrix) num_nodes = size(params.node_coords,1); % 运输成本计算 transport_cost = 0; total_distance = 0; % 仓库到第一个客户 from = depot_id; to = route(1) + num_nodes; distance = distance_matrix(from, to); transport_cost = transport_cost + (params.c1*sum(params.delivery_demand(route)) + params.c2)*distance; total_distance = total_distance + distance; % 客户间移动 for k = 2:length(route) from = route(k-1) + num_nodes; to = route(k) + num_nodes; distance = distance_matrix(from, to); remaining_delivery = sum(params.delivery_demand(route(k:end))); transport_cost = transport_cost + (params.c1*remaining_delivery + params.c2)*distance; total_distance = total_distance + distance; end % 返回仓库 from = route(end) + num_nodes; to = depot_id; distance = distance_matrix(from, to); transport_cost = transport_cost + (params.c1*sum(params.recycle_demand(route)) + params.c2)*distance; total_distance = total_distance + distance; % 修正后的结构体定义(合并字段定义) detail = struct(... 'customers', route,... % 客户顺序 'delivery_load', sum(params.delivery_demand(route)),... 'recycle_load', sum(params.recycle_demand(route)),... 'distance', total_distance,... 'transport_cost',transport_cost); total_cost = transport_cost + params.cr1 + params.c0; end %% 在主循环后调用输出函数(添加在结果显示部分) % 结果显示 disp(['最优成本:' num2str(best_cost)]); visualizeRoutes(best_solution, node_coords, customer_coords); visualizeDepotRoutes(best_solution, node_coords, customer_coords); % 分节点视图 %% 修改后的printDeliveryPlan调用 printDeliveryPlan(best_solution, struct(... 'node_coords', node_coords,... 'customer_coords', customer_coords,... 'delivery_demand', delivery_demand,... 'recycle_demand', recycle_demand,... 'depot_capacity', depot_capacity,... 'vehicle_capacity', vehicle_capacity,... 'max_distance', max_distance,... % 新增字段 'operating_cost', operating_cost,... 'cr1', cr1,... 'c0', c0,... 'c1', c1,... 'c2', c2), distance_matrix); function optimized_route = twoOptOptimization(route, distance_matrix, params) num_nodes = length(route); improved = true; best_route = route; best_cost = calculateRouteCost(route, params, distance_matrix); while improved improved = false; for i = 1:num_nodes-1 for j = i+2:num_nodes new_route = best_route; new_route(i+1:j) = new_route(j:-1:i+1); new_cost = calculateRouteCost(new_route, params, distance_matrix); if new_cost < best_cost best_route = new_route; best_cost = new_cost; improved = true; end end end end optimized_route = best_route; end function selected = tournamentSelection(population, fitness, tournament_size) pop_size = length(population); selected = cell(1, pop_size); for i = 1:pop_size candidates = randperm(pop_size, tournament_size); [~, idx] = min(fitness(candidates)); selected{i} = population{candidates(idx)}; end end function optimized_routes = optimizedSplitRoutes(route_order, depot_id, params, distance_matrix) % 调用基础函数 raw_routes = baseSplitRoutes(route_order, depot_id, params, distance_matrix); % 2-opt优化处理 optimized_routes = cellfun(@(x) twoOptOptimization(x, distance_matrix, params),... raw_routes, 'UniformOutput', false); end function transport_cost = calculateSegmentCost(segment, depot_id, params, distance_matrix) num_nodes = size(params.node_coords,1); transport_cost = 0; % 正向运输成本 current_delivery = sum(params.delivery_demand(segment)); % 配送中心到第一个客户 from = depot_id; to = segment(1) + num_nodes; distance = distance_matrix(from, to); transport_cost = transport_cost + (params.c1*current_delivery + params.c2)*distance; % 客户间运输 for k = 2:length(segment) from = segment(k-1) + num_nodes; to = segment(k) + num_nodes; distance = distance_matrix(from, to); remaining_delivery = current_delivery - sum(params.delivery_demand(segment(1:k-1))); transport_cost = transport_cost + (params.c1*remaining_delivery + params.c2)*distance; end % 逆向运输成本 recycle_load = sum(params.recycle_demand(segment)); from = segment(end) + num_nodes; to = depot_id; distance = distance_matrix(from, to); transport_cost = transport_cost + (params.c1*recycle_load + params.c2)*distance; end %% 强化路径分割与成本计算机制 % 修改后的baseSplitRoutes函数 (增加分载计数) function [vehicle_routes, vehicle_count] = enhancedSplitRoutes(route_order, depot_id, params, distance_matrix) vehicle_routes = {}; i = 1; vehicle_count = 0; % 新增车辆计数器 while i <= length(route_order) current_load = 0; segment = []; % 逐个客户装载直到容量上限 for j = i:length(route_order) customer = route_order(j); new_load = current_load + params.delivery_demand(customer) + params.recycle_demand(customer); % 分载条件检查 if new_load > params.vehicle_capacity % 当无法装载任何客户时抛出错误(应在前置检查中避免) if isempty(segment) error('客户%d需求%.1f超过单车容量%.1f',... customer,... params.delivery_demand(customer)+params.recycle_demand(customer),... params.vehicle_capacity); end break; end segment = [segment, customer]; current_load = new_load; end if ~isempty(segment) vehicle_routes{end+1} = segment; vehicle_count = vehicle_count + 1; % 每段路径计数为1辆车 i = i + length(segment); else i = i + 1; % 异常情况处理 end end end %% 修改后的成本计算逻辑 function [node_cost, vehicle_count] = calculateNodeCost(route_order, depot_id, params, distance_matrix) % 调用强化后的路径分割函数 [vehicle_routes, vehicle_count] = enhancedSplitRoutes(route_order, depot_id, params, distance_matrix); % 运输成本计算 transport_cost = 0; for v = 1:vehicle_count segment = vehicle_routes{v}; transport_cost = transport_cost + calculateSegmentCost(segment, depot_id, params, distance_matrix); end % 总成本 = 运输成本 + 固定成本×车辆数 node_cost = transport_cost + vehicle_count*(params.cr1 + params.c0); end %% 新增预处理校验函数 function validateDemands(delivery, recycle, capacity) % 检查单个客户总需求 client_total = delivery + recycle; if any(client_total > capacity) violators = find(client_total > capacity); err_msg = sprintf('客户%d总需求超标: ', violators(1)); for v = violators' err_msg = sprintf('%s\n- 客户%d: %.1f (限额%.1f)',... err_msg, v, client_total(v), capacity); end error(err_msg); end enduntitled2 函数或变量 'createChrom' 无法识别。 出错 untitled2>@(x)createChrom(size(node_coords,1),size(customer_coords,1)) (第 190 行) population = arrayfun(@(x) createChrom(size(node_coords,1), size(customer_coords,1)),... 出错 untitled2 (第 190 行) population = arrayfun(@(x) createChrom(size(node_coords,1), size(customer_coords,1)),... >>
最新发布
06-01
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值