题意:给出n段区间,每个区间后给出一个整数ci,求一个整数集Z,要求Z中的数在闭区间[ai, bi]内的个数不小于ci个,输出集合Z最少元素个数。
思路:用S[i] 表示集合Z中小于等于i的元素个数
约束条件:1. S[bi] - S[ai] >= ci; 2. S[i] - S[i-1] <= 1; 3.S[i] - S[i-1] >= 0; 以mx表示所有区间右端点的最大值,mn表示所有区间左端点的最小值,最后所求结果即为dist[mx] - dist[mn - 1]。
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<queue>
#include<vector>
#include<cstring>
using namespace std;
#define M 50005
#define INF 0x3f3f3f3f
#define mem(a) memset(a, 0, sizeof(a))
struct node
{
int to, w;
};
vector<node> arr[M];
int mx, mn;
int dist[M], vis[M], cnt[M];
int SPFA(int v0)
{
//cout << mx << " " << mn << " " << mx - mn + 2 << endl;
for (int i = mn - 1; i <= mx; i++)
{
dist[i] = INF;
}
dist[v0] = 0;
mem(vis); mem(cnt);
vis[v0]++; cnt[v0]++;
queue<int> q;
q.push(v0);
while (!q.empty())
{
int temp = q.front();
q.pop();
vis[temp]--;
for (int i = 0; i < arr[temp].size(); i++)
{
int v = arr[temp][i].to;
if (dist[v] > dist[temp] + arr[temp][i].w)
{
dist[v] = dist[temp] + arr[temp][i].w;
if (!vis[v])
{
cnt[v]++;
//cout << v << " " << cnt[v] << endl;
if (cnt[v] > mx - mn + 2)
return 1;
vis[v]++;
q.push(v);
}
}
}
}
return 0;
}
int main()
{
int n;
while (cin >> n)
{
mx = -INF; mn = INF;
for (int i = 1; i <= n; i++)\
{
int a, b, w;
scanf("%d %d %d", &a, &b, &w);
node temp;
temp.to = a-1;
temp.w = -w;
arr[b].push_back(temp);
if (a < mn)
mn = a;
if (b > mx)
mx = b;
}
for (int i = mn; i <= mx; i++)
{
node temp;
temp.to = i;
temp.w = 1;
arr[i - 1].push_back(temp);
temp.to = i - 1;
temp.w = 0;
arr[i].push_back(temp);
}
int t = SPFA(mx);
if (!t)
{
cout << -dist[mn - 1] << endl;
}
else//题目给出的条件不会出现负回路,所以这句可以不要
cout << "ERROR" << endl;
}
return 0;
}