题目:【学长带练】作物杂交
题目大意:给定一些作物的杂交关系,比如说
A
C
→
B
AC \rightarrow B
AC→B,表示
A
A
A和
C
C
C能推出
B
B
B,并且培育
A
A
A和
C
C
C种子需要一定时间,
A
A
A和
C
C
C的种子长成植物也需要一定时间。则培育
B
B
B种子的时间为
A
A
A和
C
C
C种子的培育时间最大值和
A
A
A和
B
B
B长成的最大值之和。
解题思路: 我的思路就是用拓扑排序,但是这个题有一点诡异,就是拓扑的时候需要两个点出度为0.这一句话很重要,我们知道在拓扑排序当中,栈当中的种子必须入度都是0.则在
A
C
→
B
AC \rightarrow B
AC→B的关系当中,
A
A
A和
C
C
C的入度都必须是0,才能继续对
B
B
B的培养时间进行更新。如果其中有一个种子入度不是0,那么其培育时间就不是最优的。所以维护一个数据结构如下:
vector<vector<pair<int,int>>> edge(length)
其中,
e
d
g
e
[
i
]
[
j
]
.
f
i
r
s
t
edge[i][j].first
edge[i][j].first表示第
i
i
i个种子的第
j
j
j条表达式中杂交的对象,
e
d
g
e
[
i
]
[
j
]
.
s
e
c
o
n
d
edge[i][j].second
edge[i][j].second表示产生的孩子。
这里面还需要注意,由于是双向边,所以入度减为0之后还可能被减1,所以要加判断。具体数据用这个试一下就明白了。
6 2 3 6
5 3 4 6 4 9
1 2
1 2 4
1 4 5
4 5 6
所以,代码如下:
#include<iostream>
#include<cstdio>
#include<vector>
#include<algorithm>
using namespace std;
const int length = 2e3 + 5;
int reco[length];
int linjie[length][length];
int stk[length];
int degree[length];
int vis[length];
int dp[length];
int s = 0;
int cost[length];
vector<vector<pair<int,int>>> edge(length);
int main(void)
{
int n, m, k, t;
scanf_s("%d%d%d%d", &n, &m, &k, &t);
for (int i = 1; i <= n; i++)
{
scanf_s("%d", &cost[i]);
dp[i] = INT_MAX>>1;
}
vector<int> kl;
for (int i = 0; i < m; i++)
{
int a;
scanf_s("%d", &a);
kl.push_back(a);
//vis[stk[s - 1]] = 1;
//dp[stk[s - 1]] = 0;
}
for (int i = 0; i < k; i++)
{
int a, b, c;
scanf_s("%d%d%d", &a, &b, &c);
linjie[a][b] = c;
linjie[b][a] = c;
edge[a].push_back({ b,c });
edge[b].push_back({ a,c });
degree[c]++;
}
for (int i = 0; i < m; i++)
{
if (degree[kl[i]] == 0)
{
stk[s++] = kl[i];
vis[stk[s - 1]] = 1;
dp[stk[s - 1]] = 0;
}
}
for (int i = 0; i < s; i++)
{
for (auto tmp : edge[stk[i]])
{
int j = tmp.first;
if (vis[j]&°ree[j]==0)
{
//stk[s++] = j;
int t = tmp.second;
if(degree[t]!=0)
degree[t]--;
if (!vis[t]&°ree[t]==0)
{
stk[s++] = t;
vis[t] = 1;
}
dp[t] = min(dp[t],max(cost[stk[i]], cost[j])+max(dp[stk[i]],dp[j]));
}
}
}
printf("%d", dp[t]);
}