[USACO20FEB] Timeline G
题目描述
Bessie 在过去的\(M\)天内参加了 \(N\) 次挤奶。但她已经忘了她每次挤奶是在哪个时候了。
对于第 \(i\) 次挤奶,Bessie 记得它不早于第 \(S_i\) 天进行。另外,她还有 \(C\) 条记忆,每条记忆形如一个三元组\((a,b,x)\)含义是第 \(b\) 次挤奶在第 \(a\) 次挤奶结束至少 \(x\) 天后进行。
现在请你帮 Bessie 算出在满足所有条件的前提下,每次挤奶的最早日期。
保证 Bessie 的记忆没有错误,这意味着一定存在一种合法的方案,使得:
第 \(i\) 次挤奶不早于第 \(S_i\) 天进行,且不晚于第 \(M\) 天进行;
所有的记忆都得到满足;
输入格式
第一行三个整数\(N,M,C\)。保证 \(1 \leq N,C \leq 10^5\),$ 2 \leq M \leq 10^9 $。
接下来一行包含 \(N\) 个整数\(S_1, S_2 , \ldots, S_n\),保证\(\forall 1 \leq i \leq n\),都满足\(1 \leq S_i \leq M\)。
下面 \(C\) 行每行三个整数\(a,b,x\),描述一条记忆。保证\(a \neq b\),且\(1 \leq x \leq M\) 。
输出格式
输出 $N$ 行,每行一个整数,第 $i$ 行的数表示第 $i$ 次挤奶的最早日期。
题意分析
给定C组数量关系(也就是不等式),并且给定每次挤奶的最少时间(可以转换为不等式),求每次挤奶的可能的最早时间;很明显是差分约束系统的问题
1. 三元组(a,b,x) 用 \(T_i\) 表示第i次挤奶的时间 可以得到第一组不等式 \(T_b\)-\(T_a\) \(\geq\)\(x\)。
2. 第i次挤奶不早于第\(S_i\)天 可以转换为第i次挤奶在第0次挤奶的\(S_i\)天后。
也就是 \(T_i-T_0\geq S_i\)。
那么0就成为了天然的超级源点(原因:0联通了所有点,它可以联通整张图)
3. 在符合条件的情况下,要使每次挤奶的时间尽可能的提前,而前面的挤奶时间提前会使后面的时间可能提前,即前面的最优解是后面最优解的前置条件(也就是子问题),且求解方法相同,所以我们可以使用贪心的思想。
4. 差分约束系统的问题就是建完图后求最短/长路,而求最早时间,就是求\(T_i-T_0\)的最小值,就是建形如\(X_i-X_j\geq c\)的图,然后求第0次到第i次的最长路;而贪心的思想让我们很容易想到Dijkstra算法,而天数必定为正数,那图中的边权都为正数,不会有正负交替的情况,可以使用Dijkstra算法。
Code
#include<bits/stdc++.h>
using namespace std;
struct num{
int to;
int w;
bool operator <(const num&a)const{
return w<a.w;
}//重载运算符
};
int n,m,c,a,b,x,s[100050],ans,dis[100050];
vector<num> mp[100050];
priority_queue<num> q;
void dijkstra(int s){
dis[s]=0;
q.push({s,0});
while(!q.empty()){
num u=q.top();
q.pop();
for(num i:mp[u.to]){
if(dis[i.to]<dis[u.to]+i.w){
dis[i.to]=dis[u.to]+i.w;
q.push({i.to,dis[i.to]});
}
}
}
}//最长路模板
int main(){
cin>>n>>m>>c;
for(int i=1;i<=n;i++){
cin>>s[i];//i-0>=s[i]
mp[0].push_back({i,s[i]});
}//建立超级源点
for(int i=1;i<=c;i++){
cin>>a>>b>>x;//b-a>=x
mp[a].push_back({b,x});
}//建图
dijkstra(0);
for(int i=1;i<=n;i++){
cout<<dis[i]<<endl;
}
return 0;
}

浙公网安备 33010602011771号