P1250種樹(差分約束)
阿新 • • 發佈:2019-01-04
P1250種樹
題意
給你一條街,街由N個點構成,每個點上可以種一棵樹,給你K個要求,每個要求由B,E,T組成,分別表示從點B開始到點E中間至少有T棵樹,現在問這條街上最少有幾顆樹?
資料範圍:
思路
設 sum[i]為到點i為止的字首和。
將題目的意思稍加轉換可得,求最小數量的sum[N],來使得所有要求滿足 sum[E] - sum[B-1] >= T
這樣就是求差分約束的問題了
我們可以利用最短路的計算公式, dis[u] + cost(u,v) >= dis[v]
來將其構造成一個最短路問題。即轉換成 sum[E] + (-T) >= sum[B-1]
這樣還不夠,題目中還隱藏了一些資訊,就是 每個點最多隻能種一棵,每兩個相鄰的點,後面的點值必定大於前面的點值。
最後跑一邊SPFA即可,但使用Djs好像會T。。。。。
程式碼
// luogu-judger-enable-o2
#include <bits/stdc++.h>
using namespace std;
#define rep(i,j,k) for (int i = (int)j;i <= (int)k;i ++)
#define debug(x) cerr<<#x<<":"<<x<<endl
#define pb push_back
typedef long long ll;
const int MAXN = (int)1e6+7;
const int INF = (int)0x3f3f3f3f;
struct edge{
int v,cost;
edge(int v = 0,int cost = 0):v(v),cost(cost){}
};
vector<edge> G[MAXN];
int dis[MAXN];
void SPFA(int S) {
dis[S] = 0;
queue<int> qu;
qu.push(S);
while (!qu.empty()) {
int k = qu.front();qu.pop();
rep(i,0,G[k].size()-1) {
int v = G[k][i].v;
int co = G[k][i].cost;
if (dis[v] > dis[k] + co) {
dis[v] = dis[k] + co;
qu.push(v);
}
}
}
}
int main()
{
int N,M;
scanf("%d %d",&N,&M); memset(dis,0x3f,sizeof(int)*(N+2));
rep(i,1,M) {
int u,v,w;
scanf("%d %d %d",&u,&v,&w);
G[v].pb(edge(u-1,-w));
}
rep(i,1,N) {
G[i-1].pb(edge(i,1));
G[i].pb(edge(i-1,0));
}
SPFA(N);
int mn = INF;
rep(i,0,N) {
mn = min(mn,dis[i]);
}
int ans = dis[N]-mn;
printf("%d\n",ans);
}