From 6fdae8acf307f5252ec988383605831b62d13f73 Mon Sep 17 00:00:00 2001 From: heshunme Date: Sun, 8 Sep 2024 16:15:40 +0800 Subject: [PATCH] =?UTF-8?q?=E5=AE=8C=E7=BE=8E=E4=BA=86?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- problem1-1终稿.ipynb | 995 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 995 insertions(+) create mode 100644 problem1-1终稿.ipynb diff --git a/problem1-1终稿.ipynb b/problem1-1终稿.ipynb new file mode 100644 index 0000000..e8ce878 --- /dev/null +++ b/problem1-1终稿.ipynb @@ -0,0 +1,995 @@ +{ + "cells": [ + { + "cell_type": "code", + "id": "e19ec4ae5347c678", + "metadata": { + "ExecuteTime": { + "end_time": "2024-09-08T08:14:17.258978Z", + "start_time": "2024-09-08T08:14:16.937551Z" + } + }, + "source": [ + "import numpy as np\n", + "import pandas as pd\n", + "\n", + "pd.options.display.max_columns = 100" + ], + "outputs": [], + "execution_count": 1 + }, + { + "cell_type": "code", + "id": "initial_id", + "metadata": { + "ExecuteTime": { + "end_time": "2024-09-08T08:14:17.666091Z", + "start_time": "2024-09-08T08:14:17.259867Z" + } + }, + "source": [ + "\n", + "df_crop_details = pd.read_excel('./data/2.xlsx', sheet_name=1)" + ], + "outputs": [], + "execution_count": 2 + }, + { + "cell_type": "code", + "id": "1d2a51b3414be94", + "metadata": { + "ExecuteTime": { + "end_time": "2024-09-08T08:14:17.681548Z", + "start_time": "2024-09-08T08:14:17.668092Z" + } + }, + "source": [ + "# 去除空格\n", + "df_crop_details['cropName'] = df_crop_details['cropName'].apply(lambda x: x.strip())\n" + ], + "outputs": [], + "execution_count": 3 + }, + { + "cell_type": "code", + "id": "514cd9136d9ca341", + "metadata": { + "ExecuteTime": { + "end_time": "2024-09-08T08:14:17.712692Z", + "start_time": "2024-09-08T08:14:17.682481Z" + } + }, + "source": [ + "df_crop_planting = pd.read_excel('./data/2.xlsx', sheet_name=0)\n", + "# 照例去除一下空格\n", + "df_crop_planting['cropName'] = df_crop_planting['cropName'].apply(lambda x: x.strip())\n", + "# ffill\n", + "df_crop_planting['landName'] = df_crop_planting['landName'].ffill()" + ], + "outputs": [], + "execution_count": 4 + }, + { + "cell_type": "code", + "id": "1503f8b642c842db", + "metadata": { + "ExecuteTime": { + "end_time": "2024-09-08T08:14:17.743562Z", + "start_time": "2024-09-08T08:14:17.714837Z" + } + }, + "source": [ + "df_land = pd.read_excel('./data/1.xlsx', sheet_name=0)\n", + "# 去除landType和landName的空格\n", + "df_land['landType'] = df_land['landType'].apply(lambda x: x.strip())\n", + "df_land['landName'] = df_land['landName'].apply(lambda x: x.strip())" + ], + "outputs": [], + "execution_count": 5 + }, + { + "cell_type": "code", + "id": "3cdf51a9a9d4d30f", + "metadata": { + "ExecuteTime": { + "end_time": "2024-09-08T08:14:17.759420Z", + "start_time": "2024-09-08T08:14:17.744880Z" + } + }, + "source": [ + "# 计算利润\n", + "unit_profit_lsc = []\n", + "for line in df_crop_details.values:\n", + " s = str(line[7]).split('-')\n", + " unit_profit_lsc.append((float(s[0]) + float(s[1])) / 2 * line[5] - line[6])\n", + "df_crop_details['unitProfit'] = unit_profit_lsc" + ], + "outputs": [], + "execution_count": 6 + }, + { + "cell_type": "code", + "id": "569016a9b90f841b", + "metadata": { + "ExecuteTime": { + "end_time": "2024-09-08T08:14:17.790551Z", + "start_time": "2024-09-08T08:14:17.760229Z" + } + }, + "source": [ + "df_crop_type_land = pd.read_excel('./data/1.xlsx', sheet_name=1)\n", + "# 老规矩,去掉cropName和cropType的空格\n", + "df_crop_type_land['cropType'] = df_crop_type_land['cropType'].apply(lambda x: x.strip())\n", + "df_crop_type_land['cropName'] = df_crop_type_land['cropName'].apply(lambda x: x.strip())" + ], + "outputs": [], + "execution_count": 7 + }, + { + "cell_type": "code", + "id": "a7661d84217b578c", + "metadata": { + "ExecuteTime": { + "end_time": "2024-09-08T08:14:17.806633Z", + "start_time": "2024-09-08T08:14:17.791553Z" + } + }, + "source": [ + "# 搞一下季节和年份的集合\n", + "SeasonType = [\"单季\", \"第一季\", \"第二季\"]\n", + "SeasonDict = {\"单季\": 1, \"第一季\": 1, \"第二季\": 2}\n", + "SeasonNum = [1, 2]\n", + "years = [2024, 2025, 2026, 2027, 2028, 2029, 2030]" + ], + "outputs": [], + "execution_count": 8 + }, + { + "cell_type": "code", + "id": "4a4e06a1f2d4d8ab", + "metadata": { + "ExecuteTime": { + "end_time": "2024-09-08T08:14:17.822646Z", + "start_time": "2024-09-08T08:14:17.807607Z" + } + }, + "source": [ + "# 枚举地块类型\n", + "LandType = {\"A\": \"平旱地\", \"B\": \"梯田\", \"C\": \"山坡地\", \"D\": \"水浇地\", \"E\": \"普通大棚\", \"F\": \"智慧大棚\"}" + ], + "outputs": [], + "execution_count": 9 + }, + { + "cell_type": "code", + "id": "cc938565a63a8129", + "metadata": { + "ExecuteTime": { + "end_time": "2024-09-08T08:14:17.838210Z", + "start_time": "2024-09-08T08:14:17.823659Z" + } + }, + "source": [ + "# 枚举地块\n", + "LandName = df_crop_planting['landName'].unique()" + ], + "outputs": [], + "execution_count": 10 + }, + { + "cell_type": "code", + "id": "dae53a6215cea525", + "metadata": { + "ExecuteTime": { + "end_time": "2024-09-08T08:14:17.853788Z", + "start_time": "2024-09-08T08:14:17.839182Z" + } + }, + "source": [ + "# 枚举地块面积,取df_land的landName为key,landArea为value\n", + "LandArea = {x: df_land[df_land['landName'] == x]['landArea'].values[0] for x in LandName}" + ], + "outputs": [], + "execution_count": 11 + }, + { + "cell_type": "code", + "id": "7a0e6cc209d93b56", + "metadata": { + "ExecuteTime": { + "end_time": "2024-09-08T08:14:17.869293Z", + "start_time": "2024-09-08T08:14:17.854772Z" + } + }, + "source": [ + "# 读入作物名称\n", + "CropName = df_crop_details['cropName'].unique()" + ], + "outputs": [], + "execution_count": 12 + }, + { + "cell_type": "code", + "id": "8a280f918bb3139a", + "metadata": { + "ExecuteTime": { + "end_time": "2024-09-08T08:14:17.900877Z", + "start_time": "2024-09-08T08:14:17.870289Z" + } + }, + "source": [ + "# 作物分类\n", + "CropType = {x: df_crop_type_land[df_crop_type_land['cropType'] == x]['cropName'].values for x in\n", + " df_crop_type_land['cropType'].values}\n", + "CropType['粮食(除了水稻)'] = CropType['粮食'][:-1] # 这样不太好,但能用\n", + "CropType['豆类'] = np.array(list(CropType['粮食(豆类)']) + list(CropType['蔬菜(豆类)']), dtype=object)\n", + "CropType['全粮食'] = np.array(list(CropType['粮食']) + list(CropType['粮食(豆类)']), dtype=object)\n", + "CropType['全粮食(除了水稻)'] = np.array(list(CropType['粮食'][:-1]) + list(CropType['粮食(豆类)']), dtype=object)\n", + "CropType['全蔬菜'] = np.array(list(CropType['蔬菜']) + list(CropType['蔬菜(豆类)']), dtype=object)\n", + "CropType['特殊蔬菜'] = np.array([\"大白菜\", \"白萝卜\", \"红萝卜\"], dtype=object)\n", + "CropType[\"普通蔬菜\"] = np.array([c for c in CropType['全蔬菜'] if c not in CropType['特殊蔬菜']], dtype=object)\n", + "CropType" + ], + "outputs": [ + { + "data": { + "text/plain": [ + "{'粮食(豆类)': array(['黄豆', '黑豆', '红豆', '绿豆', '爬豆'], dtype=object),\n", + " '粮食': array(['小麦', '玉米', '谷子', '高粱', '黍子', '荞麦', '南瓜', '红薯', '莜麦', '大麦', '水稻'],\n", + " dtype=object),\n", + " '蔬菜(豆类)': array(['豇豆', '刀豆', '芸豆'], dtype=object),\n", + " '蔬菜': array(['土豆', '西红柿', '茄子', '菠菜', '青椒', '菜花', '包菜', '油麦菜', '小青菜', '黄瓜',\n", + " '生菜', '辣椒', '空心菜', '黄心菜', '芹菜', '大白菜', '白萝卜', '红萝卜'], dtype=object),\n", + " '食用菌': array(['榆黄菇', '香菇', '白灵菇', '羊肚菌'], dtype=object),\n", + " '粮食(除了水稻)': array(['小麦', '玉米', '谷子', '高粱', '黍子', '荞麦', '南瓜', '红薯', '莜麦', '大麦'],\n", + " dtype=object),\n", + " '豆类': array(['黄豆', '黑豆', '红豆', '绿豆', '爬豆', '豇豆', '刀豆', '芸豆'], dtype=object),\n", + " '全粮食': array(['小麦', '玉米', '谷子', '高粱', '黍子', '荞麦', '南瓜', '红薯', '莜麦', '大麦', '水稻',\n", + " '黄豆', '黑豆', '红豆', '绿豆', '爬豆'], dtype=object),\n", + " '全粮食(除了水稻)': array(['小麦', '玉米', '谷子', '高粱', '黍子', '荞麦', '南瓜', '红薯', '莜麦', '大麦', '黄豆',\n", + " '黑豆', '红豆', '绿豆', '爬豆'], dtype=object),\n", + " '全蔬菜': array(['土豆', '西红柿', '茄子', '菠菜', '青椒', '菜花', '包菜', '油麦菜', '小青菜', '黄瓜',\n", + " '生菜', '辣椒', '空心菜', '黄心菜', '芹菜', '大白菜', '白萝卜', '红萝卜', '豇豆', '刀豆',\n", + " '芸豆'], dtype=object),\n", + " '特殊蔬菜': array(['大白菜', '白萝卜', '红萝卜'], dtype=object),\n", + " '普通蔬菜': array(['土豆', '西红柿', '茄子', '菠菜', '青椒', '菜花', '包菜', '油麦菜', '小青菜', '黄瓜',\n", + " '生菜', '辣椒', '空心菜', '黄心菜', '芹菜', '豇豆', '刀豆', '芸豆'], dtype=object)}" + ] + }, + "execution_count": 13, + "metadata": {}, + "output_type": "execute_result" + } + ], + "execution_count": 13 + }, + { + "cell_type": "code", + "id": "22f9730e3d9c1016", + "metadata": { + "ExecuteTime": { + "end_time": "2024-09-08T08:14:18.089134Z", + "start_time": "2024-09-08T08:14:17.903431Z" + } + }, + "source": [ + "# 亩产量\n", + "unit_yield_lsc = {\n", + " l: {\n", + " 1: {\n", + " c: df_crop_details[\n", + " (df_crop_details['cropName'] == c) &\n", + " (df_crop_details['cropLandType'] == l) &\n", + " ((df_crop_details['season'] == \"单季\") |\n", + " (df_crop_details['season'] == \"第一季\"))\n", + " ]['unitYield'].values[0] if df_crop_details[\n", + " (df_crop_details['cropName'] == c) &\n", + " (df_crop_details['cropLandType'] == l) &\n", + " ((df_crop_details['season'] == \"单季\") |\n", + " (df_crop_details['season'] == \"第一季\"))\n", + " ]['unitYield'].values.size > 0 else 0\n", + " for c in CropName\n", + " },\n", + " 2: {\n", + " c: df_crop_details[\n", + " (df_crop_details['cropName'] == c) &\n", + " (df_crop_details['cropLandType'] == l) &\n", + " (df_crop_details['season'] == \"第二季\")\n", + " ]['unitYield'].values[0] if df_crop_details[\n", + " (df_crop_details['cropName'] == c) &\n", + " (df_crop_details['cropLandType'] == l) &\n", + " (df_crop_details['season'] == \"第二季\")][\n", + " 'unitYield'].values.size > 0 else 0\n", + " for c in CropName\n", + " }\n", + " }\n", + " for l in LandType.values()\n", + "}\n" + ], + "outputs": [], + "execution_count": 14 + }, + { + "cell_type": "code", + "id": "99dbe4ca6c54db0b", + "metadata": { + "ExecuteTime": { + "end_time": "2024-09-08T08:14:18.292866Z", + "start_time": "2024-09-08T08:14:18.089960Z" + } + }, + "source": [ + "# 亩利润\n", + "unit_profit_lsc = {\n", + " l: {\n", + " 1: {\n", + " c: df_crop_details[\n", + " (df_crop_details['cropName'] == c) &\n", + " (df_crop_details['cropLandType'] == l) &\n", + " ((df_crop_details['season'] == \"单季\") |\n", + " (df_crop_details['season'] == \"第一季\"))\n", + " ]['unitProfit'].values[0] if df_crop_details[\n", + " (df_crop_details['cropName'] == c) &\n", + " (df_crop_details['cropLandType'] == l) &\n", + " ((df_crop_details['season'] == \"单季\") |\n", + " (df_crop_details['season'] == \"第一季\"))\n", + " ]['unitProfit'].values.size > 0 else 0\n", + " for c in CropName\n", + " },\n", + " 2: {\n", + " c: df_crop_details[\n", + " (df_crop_details['cropName'] == c) &\n", + " (df_crop_details['cropLandType'] == l) &\n", + " (df_crop_details['season'] == \"第二季\")\n", + " ]['unitProfit'].values[0] if df_crop_details[\n", + " (df_crop_details['cropName'] == c) &\n", + " (df_crop_details['cropLandType'] == l) &\n", + " (df_crop_details['season'] == \"第二季\")\n", + " ]['unitProfit'].values.size > 0 else 0\n", + " for c in CropName\n", + " }\n", + " }\n", + " for l in LandType.values()\n", + "}\n" + ], + "outputs": [], + "execution_count": 15 + }, + { + "metadata": { + "ExecuteTime": { + "end_time": "2024-09-08T08:14:18.462863Z", + "start_time": "2024-09-08T08:14:18.293865Z" + } + }, + "cell_type": "code", + "source": [ + "# 亩成本\n", + "unit_cost_lsc = {\n", + " l: {\n", + " 1: {\n", + " c: df_crop_details[\n", + " (df_crop_details['cropName'] == c) &\n", + " (df_crop_details['cropLandType'] == l) &\n", + " ((df_crop_details['season'] == \"单季\") |\n", + " (df_crop_details['season'] == \"第一季\"))\n", + " ]['cost'].values[0] if df_crop_details[\n", + " (df_crop_details['cropName'] == c) &\n", + " (df_crop_details['cropLandType'] == l) &\n", + " ((df_crop_details['season'] == \"单季\") |\n", + " (df_crop_details['season'] == \"第一季\"))\n", + " ]['cost'].values.size > 0 else 0\n", + " for c in CropName\n", + " },\n", + " 2: {\n", + " c: df_crop_details[\n", + " (df_crop_details['cropName'] == c) &\n", + " (df_crop_details['cropLandType'] == l) &\n", + " (df_crop_details['season'] == \"第二季\")\n", + " ]['cost'].values[0] if df_crop_details[\n", + " (df_crop_details['cropName'] == c) &\n", + " (df_crop_details['cropLandType'] == l) &\n", + " (df_crop_details['season'] == \"第二季\")\n", + " ]['cost'].values.size > 0 else 0\n", + " for c in CropName\n", + " }\n", + " }\n", + " for l in LandType.values()\n", + "}\n" + ], + "id": "1c8ad73eaea8be7a", + "outputs": [], + "execution_count": 16 + }, + { + "cell_type": "code", + "id": "13f2ccc7aa215d4c", + "metadata": { + "ExecuteTime": { + "end_time": "2024-09-08T08:14:18.478343Z", + "start_time": "2024-09-08T08:14:18.463669Z" + } + }, + "source": [ + "# 每种作物的总需求\n", + "crop_demand = {\n", + " c: 0\n", + " for c in CropName\n", + "}\n", + "\n", + "# 这里需要另一张表\n", + "# 代码独立出来移到上面去了\n", + "\n", + "for line in df_crop_planting.values:\n", + " # 面积*该土地类型的亩产量 面积 地块类型字典 地块类型 季节 作物名称\n", + " crop_demand[line[2]] += line[4] * unit_yield_lsc[LandType[line[0][0]]][SeasonDict[line[5]]][line[2]]\n" + ], + "outputs": [], + "execution_count": 17 + }, + { + "cell_type": "code", + "id": "5d09872708d40da4", + "metadata": { + "ExecuteTime": { + "end_time": "2024-09-08T08:14:18.525244Z", + "start_time": "2024-09-08T08:14:18.480029Z" + } + }, + "source": [ + "# 准备开搞\n", + "from pulp import LpMaximize, LpProblem, LpVariable, lpSum, value, PULP_CBC_CMD, LpContinuous, LpBinary\n", + "import pulp" + ], + "outputs": [], + "execution_count": 18 + }, + { + "cell_type": "code", + "id": "b6eff87c7a762769", + "metadata": { + "ExecuteTime": { + "end_time": "2024-09-08T08:14:18.541546Z", + "start_time": "2024-09-08T08:14:18.527235Z" + } + }, + "source": [ + "model = LpProblem(\"Crop_Planting_Optimization_with_Specific_Rules\", LpMaximize)" + ], + "outputs": [], + "execution_count": 19 + }, + { + "cell_type": "code", + "id": "4cb129e20385a7ee", + "metadata": { + "ExecuteTime": { + "end_time": "2024-09-08T08:14:18.587814Z", + "start_time": "2024-09-08T08:14:18.542556Z" + } + }, + "source": [ + "\n", + "t = []\n", + "for y in years:\n", + " for l in LandName:\n", + " for s in SeasonNum:\n", + " if l[0] in [\"A\", \"B\", \"C\"] and s == 1:\n", + " for c in CropType[\"全粮食(除了水稻)\"]:\n", + " t.append((c, l, y, s))\n", + " if l[0] == \"D\":\n", + " if s == 1:\n", + " for c in list(CropType[\"普通蔬菜\"]) + [\"水稻\"]:\n", + " t.append((c, l, y, s))\n", + " if s == 2:\n", + " for c in CropType[\"特殊蔬菜\"]:\n", + " t.append((c, l, y, s))\n", + " if l[0] == \"E\":\n", + " if s == 1:\n", + " for c in list(CropType[\"普通蔬菜\"]):\n", + " t.append((c, l, y, s))\n", + " if s == 2:\n", + " for c in CropType[\"食用菌\"]:\n", + " t.append((c, l, y, s))\n", + " if l[0] == \"F\":\n", + " for s in SeasonNum:\n", + " for c in CropType[\"普通蔬菜\"]:\n", + " t.append((c, l, y, s))\n", + "\n", + "\n", + "# X" + ], + "outputs": [], + "execution_count": 20 + }, + { + "metadata": { + "ExecuteTime": { + "end_time": "2024-09-08T08:14:18.618675Z", + "start_time": "2024-09-08T08:14:18.589714Z" + } + }, + "cell_type": "code", + "source": [ + "# 地块l在y年的s季的种植c的量\n", + "X = LpVariable.dicts(\"X\", t,\n", + " lowBound=0,\n", + " cat=LpContinuous\n", + " )" + ], + "id": "ca23e006a68f2993", + "outputs": [], + "execution_count": 21 + }, + { + "cell_type": "code", + "id": "9dab983ca7b3b607", + "metadata": { + "ExecuteTime": { + "end_time": "2024-09-08T08:14:18.649531Z", + "start_time": "2024-09-08T08:14:18.619566Z" + } + }, + "source": [ + "# 地块l在y年的s季是否种植了c\n", + "Y = LpVariable.dicts(\"Y\", t, cat=LpBinary)" + ], + "outputs": [], + "execution_count": 22 + }, + { + "metadata": { + "ExecuteTime": { + "end_time": "2024-09-08T08:14:18.664701Z", + "start_time": "2024-09-08T08:14:18.650399Z" + } + }, + "cell_type": "code", + "source": [ + "tt = set(t)\n", + "\n", + "\n", + "def is_feasible(c, l, y, s):\n", + " return (c, l, y, s) in tt" + ], + "id": "bf16c7f3ea10152f", + "outputs": [], + "execution_count": 23 + }, + { + "metadata": { + "ExecuteTime": { + "end_time": "2024-09-08T08:14:19.068077Z", + "start_time": "2024-09-08T08:14:18.665729Z" + } + }, + "cell_type": "code", + "source": [ + "# 确保与X进行01约束\n", + "for c in CropName:\n", + " for l in LandName:\n", + " for y in years:\n", + " for s in SeasonNum:\n", + " # if 1:\n", + " if is_feasible(c, l, y, s):\n", + " # 如果种植了作物,则种植面积大于0\n", + " model += X[c, l, y, s] <= 100 * Y[c, l, y, s], f\"PlantingConstraint1_{c}_{l}_{y}_{s}\"\n", + " # 如果未种植作物,则种植面积为0\n", + " model += X[c, l, y, s] >= 0.001 * Y[c, l, y, s], f\"PlantingConstraint2_{c}_{l}_{y}_{s}\"\n", + "\n", + "min_area = 0.2\n", + "for c in CropName:\n", + " for l in LandName:\n", + " for y in years:\n", + " for s in SeasonNum:\n", + " if is_feasible(c, l, y, s):\n", + " model += X[c, l, y, s] <= LandArea[l] * Y[c, l, y, s], f\"LandAreaConstraint_{c}_{l}_{y}_{s}\"\n", + " model += X[c, l, y, s] >= min_area * (\n", + " 1 if Y[c, l, y, s] else 0), f\"MinAreaConstraint_{c}_{l}_{y}_{s}\"" + ], + "id": "603175d36624172f", + "outputs": [], + "execution_count": 24 + }, + { + "metadata": { + "ExecuteTime": { + "end_time": "2024-09-08T08:14:19.177480Z", + "start_time": "2024-09-08T08:14:19.069076Z" + } + }, + "cell_type": "code", + "source": [ + "# 初始化总目标函数的表达式\n", + "total_profit = lpSum([]) # 空的lpSum用于初始化\n", + "\n", + "# 累积每个作物、每个年份的利润和惩罚\n", + "for c in CropName:\n", + " for y in years:\n", + " # 计算利润部分\n", + " profit_term = lpSum(\n", + " X[c, l, y, s] * unit_profit_lsc[LandType[l[0]]][s][c]\n", + " for l in LandName for s in SeasonNum if is_feasible(c, l, y, s)\n", + " )\n", + " \n", + " # 惩罚超过需求的部分:将每个地块、每个季节的单位成本与种植量相乘\n", + " penalty_term = lpSum(\n", + " X[c, l, y, s] * unit_cost_lsc[LandType[l[0]]][s][c]\n", + " for l in LandName for s in SeasonNum if is_feasible(c, l, y, s)\n", + " ) - crop_demand[c] * lpSum(\n", + " unit_cost_lsc[LandType[l[0]]][s][c]\n", + " for l in LandName for s in SeasonNum if is_feasible(c, l, y, s)\n", + " )\n", + " \n", + " # 累积到总目标函数中\n", + " total_profit += profit_term - penalty_term\n", + "\n", + "# 一次性将目标函数添加到模型中\n", + "model += total_profit, \"total_profit\"\n" + ], + "id": "4505b0f2fe6bf93d", + "outputs": [], + "execution_count": 25 + }, + { + "metadata": { + "ExecuteTime": { + "end_time": "2024-09-08T08:14:19.193505Z", + "start_time": "2024-09-08T08:14:19.178490Z" + } + }, + "cell_type": "code", + "source": [ + "# # 添加需求约束\n", + "# for c in CropName:\n", + "# for y in years:\n", + "# model += lpSum(\n", + "# X[c, l, y, s] for l in LandName for s in SeasonNum if is_feasible(c, l, y, s)\n", + "# ) <= crop_demand[c] + Excess[c, y], f\"demand_constraint_{c}_{y}\"" + ], + "id": "a2fe5874538f1596", + "outputs": [], + "execution_count": 26 + }, + { + "cell_type": "code", + "id": "7e13de7700d38f19", + "metadata": { + "ExecuteTime": { + "end_time": "2024-09-08T08:14:19.225057Z", + "start_time": "2024-09-08T08:14:19.195511Z" + } + }, + "source": [ + "# 条件2: 每年每季每块地的种植面积不能超过该地块的总面积\n", + "for l in LandName:\n", + " for y in years:\n", + " for s in SeasonNum:\n", + " model += lpSum(X[c, l, y, s] for c in CropName if is_feasible(c, l, y, s)) <= LandArea[\n", + " l], f\"LandAreaConstraint_{l}_{y}_{s}\"" + ], + "outputs": [], + "execution_count": 27 + }, + { + "cell_type": "code", + "id": "1f6ac4323825f28b", + "metadata": { + "ExecuteTime": { + "end_time": "2024-09-08T08:14:19.240711Z", + "start_time": "2024-09-08T08:14:19.226182Z" + } + }, + "source": [ + "# 条件3: 平旱地、梯田和山坡地每年适宜单季种植[粮食类作物(水稻除外)]。因为除了[粮食类作物(水稻除外)]以外的作物似乎已经被上面给约束了,所以大概不需要做限制了吧\n", + "for l in LandName:\n", + " if l[0] in [\"A\", \"B\", \"C\"]: # [\"平旱地\", \"梯田\", \"山坡地\"]\n", + " for y in years:\n", + " model += lpSum(\n", + " Y[c, l, y, 2] for c in CropName if is_feasible(c, l, y, 2)) == 0, f\"SingleSeasonConstraint1_{y}_{l}\"\n", + "\n" + ], + "outputs": [], + "execution_count": 28 + }, + { + "cell_type": "code", + "id": "c0e9b6b37092f0e7", + "metadata": { + "ExecuteTime": { + "end_time": "2024-09-08T08:14:19.256292Z", + "start_time": "2024-09-08T08:14:19.241709Z" + } + }, + "source": [ + "# 条件4: 水浇地每年可以单季种植水稻或两季种植蔬菜作物。\n", + "for l in LandName:\n", + " if l[0] == \"D\":\n", + " for y in years:\n", + " for c in CropType[\"全蔬菜\"]:\n", + " if is_feasible(c,l,y,2):\n", + " model += Y[\"水稻\", l, y, 1] + Y[c, l, y, 2] <= 1, f\"IrrigatedConstraint0_{l}_{y}_{c}\"\n" + ], + "outputs": [], + "execution_count": 29 + }, + { + "cell_type": "code", + "id": "e8fb2dea1326a05b", + "metadata": { + "ExecuteTime": { + "end_time": "2024-09-08T08:14:19.287009Z", + "start_time": "2024-09-08T08:14:19.257188Z" + } + }, + "source": [ + "# 条件10: 别种得太碎了,啥意思? 每种作物不超过4块地吧。\n", + "for c in CropName:\n", + " for y in years:\n", + " for s in SeasonNum:\n", + " model += lpSum(\n", + " Y[c, l, y, s] for l in LandName if is_feasible(c, l, y, s)) <= 3, f\"MaxCropTypeConstraint_{c}_{y}_{s}\"" + ], + "outputs": [], + "execution_count": 30 + }, + { + "metadata": { + "ExecuteTime": { + "end_time": "2024-09-08T08:14:19.333885Z", + "start_time": "2024-09-08T08:14:19.288072Z" + } + }, + "cell_type": "code", + "source": [ + "# 条件11: 每块地最大种植作物种类数3\n", + "for l in LandName:\n", + " for y in years:\n", + " for s in SeasonNum:\n", + " model += lpSum(\n", + " Y[c, l, y, s] for c in CropName if is_feasible(c, l, y, s)) <= 3, f\"MaxLandConstraint_{l}_{y}_{s}\"" + ], + "id": "b8d9ae82090818ec", + "outputs": [], + "execution_count": 31 + }, + { + "cell_type": "code", + "id": "49f1490823c6af3c", + "metadata": { + "ExecuteTime": { + "end_time": "2024-09-08T08:14:19.411639Z", + "start_time": "2024-09-08T08:14:19.335783Z" + } + }, + "source": [ + "# 条件12: 最小种植面积:0.2吧\n", + "for l in LandName:\n", + " for y in years:\n", + " for s in SeasonNum:\n", + " for c in CropName:\n", + " if is_feasible(c, l, y, s):\n", + " model += X[c, l, y, s] >= 0.2 * (\n", + " 1 if X[c, l, y, s] else 0), f\"MinCropAreaConstraint_{c}_{l}_{y}_{s}\"" + ], + "outputs": [], + "execution_count": 32 + }, + { + "cell_type": "code", + "id": "bdf1048b83723f91", + "metadata": { + "ExecuteTime": { + "end_time": "2024-09-08T08:14:19.473674Z", + "start_time": "2024-09-08T08:14:19.412530Z" + } + }, + "source": [ + "# 条件13 : 最重要的,不能重复种植同一块地同一年同一季的同一作物\n", + "# 每种作物在同一地块(含大棚)都不能连续重茬种植\n", + "\n", + "for l in LandName:\n", + " for c in CropName:\n", + " for y in years[1:]: # 单季不能连年种植 同一年不能连续种植 跨年也不能连续种植\n", + " if is_feasible(c, l, y - 1, 1) and is_feasible(c, l, y - 1, 2):\n", + " model += Y[c, l, y - 1, 1] + Y[c, l, y - 1, 2] <= 1, f\"RepeatPlantingConstraint_{c}_{l}_{y}\"\n", + " model += Y[c, l, y - 1, 2] + Y[c, l, y, 1] <= 1, f\"RepeatPlantingConstraint1_{c}_{l}_{y}\"\n", + " if is_feasible(c, l, y - 1, 1) and is_feasible(c, l, y, 1):\n", + " if l[0] in [\"A\", \"B\", \"C\"]: # and c in CropType[\"全粮食\"]:\n", + " model += Y[c, l, y - 1, 1] + Y[c, l, y, 1] <= 1, f\"RepeatPlantingConstraint2_{c}_{l}_{y}\"\n", + " elif l[0] == \"D\" and c == \"水稻\":\n", + " model += Y[c, l, y - 1, 1] + Y[c, l, y, 1] <= 1, f\"RepeatPlantingConstraint3_{c}_{l}_{y}\"\n" + ], + "outputs": [], + "execution_count": 33 + }, + { + "cell_type": "code", + "id": "50da0aff9c68ae24", + "metadata": { + "ExecuteTime": { + "end_time": "2024-09-08T08:14:19.488304Z", + "start_time": "2024-09-08T08:14:19.474674Z" + } + }, + "source": [ + "# 条件14:从 2023 年开始,要求每个地块(含大棚) 在三年内至少种满一次豆类作物\n", + "for l in LandName:\n", + " for y in years[2:]: # 只需循环到倒数第三年,因为要考虑三年周期\n", + " # 在 y-2 到 y+2 之间的三年内,至少种满一次豆类作物\n", + " model += lpSum(X[c, l, y_r, s]\n", + " for c in CropType['豆类']\n", + " for y_r in range(y - 2, y + 1)\n", + " for s in SeasonNum if is_feasible(c, l, y_r, s)) >= LandArea[l], f\"BeanConstraint_{l}_{y}\"\n" + ], + "outputs": [], + "execution_count": 34 + }, + { + "cell_type": "code", + "id": "d4792a1210afca3b", + "metadata": { + "ExecuteTime": { + "end_time": "2024-09-08T08:14:33.144757Z", + "start_time": "2024-09-08T08:14:19.489518Z" + } + }, + "source": [ + "%%time\n", + "model.solve(\n", + " pulp.GUROBI_CMD(msg=True,\n", + " timeLimit=7200,\n", + " threads=20,\n", + " options=[(\"Method\", 2), (\"MIPGap\", 0.0001)]))\n" + ], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "CPU times: total: 78.1 ms\n", + "Wall time: 13.6 s\n" + ] + }, + { + "data": { + "text/plain": [ + "1" + ] + }, + "execution_count": 35, + "metadata": {}, + "output_type": "execute_result" + } + ], + "execution_count": 35 + }, + { + "cell_type": "code", + "id": "cb3f4e95111e3292", + "metadata": { + "ExecuteTime": { + "end_time": "2024-09-08T08:14:33.570095Z", + "start_time": "2024-09-08T08:14:33.146145Z" + } + }, + "source": [ + "# 输出文件名,包含起始年份和结束年份\n", + "output_filename = f\"planting_plan_1_1_{years[0]}-{years[-1]}.xlsx\"\n", + "\n", + "with pd.ExcelWriter(output_filename) as writer:\n", + " for y in years:\n", + "\n", + " # 用于存储需要交换的DataFrame\n", + " sheets_to_swap = {}\n", + "\n", + " for s in SeasonNum:\n", + " # 创建一个空的 DataFrame,横轴为作物名称,纵轴为地块名称\n", + " result_table = pd.DataFrame(columns=CropName, index=LandName)\n", + "\n", + " # 填充表格数据\n", + " for l in LandName:\n", + " for c in CropName:\n", + " # 获取变量 X[c, l, y, s] 的值\n", + " if is_feasible(c, l, y, s):\n", + " crop_value = value(X[c, l, y, s])\n", + " if crop_value is not None and crop_value > 0:\n", + " result_table.at[l, c] = crop_value # 填入结果\n", + "\n", + " # 用 0 填充空值\n", + " result_table.fillna(0, inplace=True)\n", + " sheet_name = f\"{y}_Season_第{s}季\"\n", + " result_table.to_excel(writer, sheet_name=sheet_name)\n", + "\n", + "print(f\"结果已保存到文件:{output_filename}\")\n" + ], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "结果已保存到文件:planting_plan_1_1_2024-2030.xlsx\n" + ] + } + ], + "execution_count": 36 + }, + { + "cell_type": "code", + "id": "ebbf10d3", + "metadata": { + "ExecuteTime": { + "end_time": "2024-09-08T08:14:33.943958Z", + "start_time": "2024-09-08T08:14:33.571680Z" + } + }, + "source": [ + "# 四舍五入版\n", + "output_filename = f\"planting_plan_1_1_{years[0]}-{years[-1]}-四舍五入版.xlsx\"\n", + "\n", + "with pd.ExcelWriter(output_filename) as writer:\n", + " for y in years:\n", + " # 用于存储需要交换的DataFrame\n", + " sheets_to_swap = {}\n", + "\n", + " for s in SeasonNum:\n", + " # 创建一个空的 DataFrame,横轴为作物名称,纵轴为地块名称\n", + " result_table = pd.DataFrame(columns=CropName, index=LandName)\n", + "\n", + " # 填充表格数据\n", + " for l in LandName:\n", + " for c in CropName:\n", + " # 获取变量 X[c, l, y, s] 的值\n", + " if is_feasible(c, l, y, s):\n", + " crop_value = value(X[c, l, y, s])\n", + " if crop_value is not None and crop_value > 0:\n", + " result_table.at[l, c] = crop_value # 填入结果\n", + "\n", + " # 用 0 填充空值\n", + " result_table.fillna(0, inplace=True)\n", + "\n", + " # 对DataFrame中的所有数值进行四舍五入,保留两位小数\n", + " result_table = result_table.round(2)\n", + "\n", + " sheet_name = f\"{y}_Season_第{s}季\"\n", + " result_table.to_excel(writer, sheet_name=sheet_name)\n" + ], + "outputs": [], + "execution_count": 37 + }, + { + "metadata": { + "ExecuteTime": { + "end_time": "2024-09-08T08:14:33.959313Z", + "start_time": "2024-09-08T08:14:33.944640Z" + } + }, + "cell_type": "code", + "source": "", + "id": "ab1fd16df70c4293", + "outputs": [], + "execution_count": 37 + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3 (ipykernel)", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.9.17" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +}