题目描述
John
的农场在给奶牛挤奶前有很多杂务要完成,每一项杂务都需要一定的时间来完成它。比如:他们要将奶牛集合起来,将他们赶进牛棚,为奶牛清洗乳房以及一些其它工作。尽早将所有杂务完成是必要的,因为这样才有更多时间挤出更多的牛奶。当然,有些杂务必须在另一些杂务完成的情况下才能进行。比如:只有将奶牛赶进牛棚才能开始为它清洗乳房,还有在未给奶牛清洗乳房之前不能挤奶。我们把这些工作称为完成本项工作的准备工作。至少有一项杂务不要求有准备工作,这个可以最早着手完成的工作,标记为杂务111。John
有需要完成的nnn个杂务的清单,并且这份清单是有一定顺序的,杂务k(k>1)k(k>1)k(k>1)的准备工作只可能在杂务111至k−1k-1k−1中。
写一个程序从111到nnn读入每个杂务的工作说明。计算出所有杂务都被完成的最短时间。当然互相没有关系的杂务可以同时工作,并且,你可以假定John
的农场有足够多的工人来同时完成任意多项任务。
输入格式
第1行:一个整数nnn,必须完成的杂务的数目(3≤n≤10,0003 \le n \le 10,0003≤n≤10,000);
第222至(n+1)(n+1)(n+1)行: 共有nnn行,每行有一些用111个空格隔开的整数,分别表示:
* 工作序号(111至nnn,在输入文件中是有序的);
* 完成工作所需要的时间len(1≤len≤100)len(1 \le len \le 100)len(1≤len≤100);
* 一些必须完成的准备工作,总数不超过100100100个,由一个数字000结束。有些杂务没有需要准备的工作只描述一个单独的000,整个输入文件中不会出现多余的空格。
输出格式
一个整数,表示完成所有杂务所需的最短时间。
输入输出样例
输入 #1
7
1 5 0
2 2 1 0
3 3 2 0
4 6 1 0
5 1 2 4 0
6 8 2 4 0
7 4 3 5 6 0
输出 #1复制
23
题目大意 : 输入一个N, 接下来有N行, 每行前两个数代表序号和该序号完工需要花费的时间, 接下来输入一个数直到他 == 0, 表示只有完成这个数的工作完成才能进行该开头输入的数的工作, 输出完成所有工作的最短时间
思路 : 写完这题后看了下题解,几乎没有我这么做的, 基本都是DP、拓扑排序,不过想法大同小异。 之前也做过一道类似的带限制最短路的题, 基本思路就是, 当一个点不受限制后就将他入队, 在输入的过程中, 把每个点都处理下并建立超级源点和超级汇点(防止一开始可以进行很多工作和很多工作可能同时结束),如果这个点没有限制他的点, 那么就将他与源点相连, 如果某个点不限制其他的点, 那么一定是最后结束的,将他和汇点相连,观察后可以发现,每个点的最短完成时间,一定是限制他的所有点的完成时间的最大值 + 该点的完工时间, 这个就是最短路的更新条件。 一切处理完毕, 直接从源点到汇点跑一次最短路,就解决了。
Accepted code
#include<bits/stdc++.h>
using namespace std;
#define sc scanf
#define ls rt << 1
#define rs ls | 1
#define Min(x, y) x = min(x, y)
#define Max(x, y) x = max(x, y)
#define ALL(x) (x).begin(),(x).end()
#define SZ(x) ((int)(x).size())
#define MEM(x, b) memset(x, b, sizeof(x))
#define lowbit(x) ((x) & (-x))
#define P2(x) ((x) * (x))
typedef long long ll;
const int MOD = 1e9 + 7;
const int MAXN = 1e5 + 10;
const int INF = 0x3f3f3f3f;
inline ll fpow(ll a, ll b){ ll r = 1, t = a; while (b){ if (b & 1)r = (r*t) % MOD; b >>= 1; t = (t*t) % MOD; }return r; }
struct node
{
int id, w;
bool operator < (const node &oth) const
{
return w > oth.w;
}
}mid;
int n, m, sp, tp;
int dis[MAXN], in[MAXN], val[MAXN];
vector <int> e[MAXN << 1];
vector <int> edge[MAXN << 1];
void dijkstra(int u) {
MEM(dis, INF); priority_queue <node> q;
q.push({ u, 0 }); dis[u] = 0;
while (!q.empty()) {
mid = q.top();
q.pop();
int ans = mid.id;
if (dis[ans] != mid.w) continue;
for (int i = 0; i < e[ans].size(); i++) {
int vi = e[ans][i];
in[vi]--;
if (!in[vi]) { // 没有限制就入队
int max_ = -1;
for (int j = 0; j < edge[vi].size(); j++)
max_ = max(max_, dis[edge[vi][j]] + val[vi]);
dis[vi] = max_; // 更新最短路
q.push({ vi, dis[vi] });
}
}
}
}
int main()
{
cin >> n;
sp = 0, tp = n + 1;
for (int i = 1; i <= n; i++) {
int ui, vi, wi;
sc("%d %d", &ui, &wi);
val[ui] = wi;
int tot = 0;
while (sc("%d", &vi) && vi) {
tot++; in[ui]++;
e[vi].push_back(ui);
edge[ui].push_back(vi);
}
if (!tot){ // 不被其他店限制,一定要先走
e[sp].push_back(i);
edge[i].push_back(sp);
in[i]++;
}
}
for (int i = 1; i <= n; i++) { // 不限制其他点, 一定最后走
if (e[i].size() == 0) {
e[i].push_back(tp);
edge[tp].push_back(i);
in[tp]++;
}
}
dijkstra(sp);
cout << dis[tp] << endl;
return 0;
}