问题
题目描述
作物杂交是作物栽培中重要的一步。已知有 N 种作物 (编号 1 至 N ),第 i 种作物从播种到成熟的时间为 Ti。作物之间两两可以进行杂交,杂交时间取两种中时间较长的一方。如作物 A 种植时间为 5 天,作物 B 种植时间为 7 天,则 AB 杂交花费的时间为 7 天。作物杂交会产生固定的作物,新产生的作物仍然属于 N 种作物中的一种。
初始时,拥有其中 M 种作物的种子 (数量无限,可以支持多次杂交)。同时可以进行多个杂交过程。求问对于给定的目标种子,最少需要多少天能够得到。
如存在 4 种作物 ABCD,各自的成熟时间为 5 天、7 天、3 天、8 天。初始拥有 AB 两种作物的种子,目标种子为 D,已知杂交情况为 A × B → C,A × C → D。则最短的杂交过程为:
第 1 天到第 7 天 (作物 B 的时间),A × B → C。
第 8 天到第 12 天 (作物 A 的时间),A × C → D。
花费 12 天得到作物 D 的种子。
输入描述
输入的第 1 行包含 4 个整数 N, M, K, T:
N 表示作物种类总数 (编号 1 至 N),M 表示初始拥有的作物种子类型数量,K 表示可以杂交的方案数,T 表示目标种子的编号。
第 2 行包含 N 个整数:
其中第 i 个整数表示第 i 种作物的种植时间 Ti(1 ≤ Ti ≤ 100)。
第 3 行包含 M 个整数:
分别表示已拥有的种子类型 Kj(1 ≤ Kj ≤ M),Kj两两不同。
第 4 至 K + 3 行:
每行包含 3 个整数 A, B,C,表示第 A 类作物和第 B 类作物杂交可以获得第 C 类作物的种子。
其中,1 ≤ N ≤ 2000, 2 ≤ M ≤ N , 1 ≤ K ≤ 10 的 5次方,1 ≤ T ≤ N, 保证目标种子一定可以通过杂交得到。
输出描述
输出一个整数,表示得到目标种子的最短杂交时间。
输入输出样例
输入
6 2 4 6
5 3 4 6 4 9
1 2
1 2 3
1 3 4
2 3 5
4 5 6
输出
16
样例说明
第 1 天至第 5 天,将编号 1 与编号 2 的作物杂交,得到编号 3 的作物种子。
第 6 天至第 10 天,将编号 1 与编号 3 的作物杂交,得到编号 4 的作物种子。
第 6 天至第 9 天,将编号 2 与编号 3 的作物杂交,得到编号 5 的作物种子。
第 11 天至第 16 天,将编号 4 与编号 5 的作物杂交,得到编号 6 的作物种子。
总共花费 16 天。
运行限制
- 最大运行时间:1s
- 最大运行内存:256M
尝试解题
问题等价于已知一个品种到另一种的杂交节点和路线,然后找出最短路径,我一开始想到的是用图的求最短路径来解决,但是到了实际实现的时候发现图论没办法体现每个子代和双亲的一对多条件关系,然后上网一查看有人用的dfs(深搜),以及有些人提及的倒序,从目标作物开始查找双亲,具体实现如下,从目标出发,每层dfs返回参数对应的种子的最短培育时间,最内层的递归判断本层的种子是否已拥有,若既无杂交方案也不已经存在,返回非正值-1作为标记,以便上层放弃这个方案分支;如果存在逐层返回得到本层对应目标的最短杂交时间,最后第一层得到目标种子目标答案, 目前代码在样例这种没有闭环的小规模数据上能正确输出,放到蓝桥杯oj后,推测是数据存在无用且带闭环的分支,补充了一部分代码进行剪枝,但是好像没有成功实现,可能需要画个图研究一下剪枝和破环的代码逻辑哪儿有问题(2021/04/16).
#include <stdio.h>
#include <stdlib.h>
using namespace std;
#define MAXSIZE 2000
#define day_need x
#define indict y
#define if_have z
#define parenta x
#define parentb y
#define child z
typedef struct int_node {
int data;
int_node* next;
}node;
typedef struct Triplet {
int x;
int y;
int z;
}Triplet;
Triplet* crosstarget_triplet;
Triplet* seeddata_triplet;
int* if_inroute;
int rank_max, rank_now, solutions_num_max, solutions_num_now, target_num;
int days_indeed = MAXSIZE;
void init();
int dfs(int Child);
// void crosstarget_insert(int parentA, int parentB, int Child);
int main() {
init();
days_indeed = dfs(target_num);
printf("%d", days_indeed);
return 0;
}
void crosstarget_insert(int parentA, int parentB, int Child) {
if (parentA > parentB)// 小在前,保持有序
{
int temp = parentA;
parentA = parentB;
parentB = temp;
}
for (int i = solutions_num_now + 1; i > seeddata_triplet[parentA + 1].indict; i--)
{
crosstarget_triplet[i].parenta = crosstarget_triplet[i - 1].parenta;
crosstarget_triplet[i].parentb = crosstarget_triplet[i - 1].parentb;
crosstarget_triplet[i].child = crosstarget_triplet[i - 1].child;
}
crosstarget_triplet[seeddata_triplet[parentA + 1].indict].parenta = parentA;
crosstarget_triplet[seeddata_triplet[parentA + 1].indict].parentb = parentB;
crosstarget_triplet[seeddata_triplet[parentA + 1].indict].child = Child;
for (int i = parentA + 1; i < rank_max; i++)
{
seeddata_triplet[i].indict++;
}
}
node* get_parents_indict(int Child) {
node* head = (node*)malloc(sizeof(node)), * p = NULL;
if (head == NULL)
{
return NULL;
}
head->data = -1;
head->next = NULL;
for (int i = 1; i <= solutions_num_max; i++)
{
if (crosstarget_triplet[i].child == Child)
{
if (p == NULL)
{
p = head;
}
p->data = i;
p->next = (node*)malloc(sizeof(node));
p = p->next;
if (p == NULL)
{
return head;
}
p->data = -1;
p->next = NULL;
}
}
return head;
}
void free_nodes(node* head) {
while (true)
{
node* p = head, * q = NULL;
while (p->next != NULL)
{
q = p;
p = p->next;
}
if (p == head)
{
free(head);
break;
}
free(p);
q->next = NULL;
}
}
int get_a_cross_day_inneed(int Indict) {
return seeddata_triplet[crosstarget_triplet[Indict].parenta].day_need > seeddata_triplet[crosstarget_triplet[Indict].parentb].day_need ?
seeddata_triplet[crosstarget_triplet[Indict].parenta].day_need : seeddata_triplet[crosstarget_triplet[Indict].parentb].day_need;
}
void init() {
// 第一行
scanf("%d%d%d%d", &rank_max, &rank_now, &solutions_num_max, &target_num);
crosstarget_triplet = (Triplet*)malloc(sizeof(Triplet) * (solutions_num_max + 1));
seeddata_triplet = (Triplet*)malloc(sizeof(Triplet) * (rank_max + 1));
if_inroute = (int*)malloc(sizeof(int) * (rank_max + 1));
//第二行
for (int i = 1; i <= rank_max; i++)
{
scanf("%d", &seeddata_triplet[i].day_need);
seeddata_triplet[i].indict = 1;
seeddata_triplet[i].if_have = 0;
if_inroute[i] = 0;
}
// 第三行
for (int i = 1; i <= rank_now; i++)
{
int seed_num;
scanf("%d", &seed_num);
seeddata_triplet[seed_num].if_have = 1;
}
// 第四行
for (solutions_num_now = 0; solutions_num_now < solutions_num_max; solutions_num_now++)
{
int parentA, parentB, Child;
scanf("%d%d%d", &parentA, &parentB, &Child);
crosstarget_insert(parentA, parentB, Child);
}
}
int dfs(int Child)// 递归返回获得每个种子的用时
{
if (seeddata_triplet[Child].if_have == 1)
{
return 0;
}
else if (seeddata_triplet[Child].if_have == -1)
{
return -1;
}
else
{
node* head = get_parents_indict(Child);
if (head->data == -1)
{
free(head);
seeddata_triplet[Child].if_have = -1;
return -1;
}
node* temp_node = head;
int temp_days = 0;
if_inroute[Child] = 1;
while (head->data != -1)
{
int temp_indict = head->data;
if (if_inroute[crosstarget_triplet[temp_indict].parenta] == 1 || if_inroute[crosstarget_triplet[temp_indict].parentb] == 1)
{
printf("Child:%d\n", Child);
head = head->next;
free(temp_node);
temp_node = head;
continue;
}
if (seeddata_triplet[crosstarget_triplet[temp_indict].parenta].if_have == -1 || seeddata_triplet[crosstarget_triplet[temp_indict].parentb].if_have == -1)
{
head = head->next;
free(temp_node);
temp_node = head;
continue;
}
int to_getPA = dfs(crosstarget_triplet[temp_indict].parenta);
int to_getPB = dfs(crosstarget_triplet[temp_indict].parentb);
int temp = (to_getPA > to_getPB ? to_getPA : to_getPB) + get_a_cross_day_inneed(temp_indict);
if (temp_days > temp || temp_days == 0)
{
temp_days = temp;
}
head = head->next;
free(temp_node);
temp_node = head;
}
free(temp_node);
if_inroute[Child] = 0;
if (temp_days != 0)
{
return temp_days;
}
else
{
seeddata_triplet[Child].if_have = -1;
return -1;
}
}
}