POJ 1201 Intervals (차동 제약 시스템, 욕심 + 선분 트 리)
제목
최대 50000 개의 정수 구간 과 이 구간 에 적어도 포 함 된 정수 의 개 수 를 요구 합 니 다.
지금 은 원소 의 수량 이 가장 적은 정수 집합 을 찾 아 상기 조건 을 만족 시 키 고 가장 적은 원소 의 개수 가 얼마 인지 물 어 봐 야 한다.
문제 풀이 방법
방법 1 차 제약 시스템
d [i] 는 0 - > i - 1 구간 에 포 함 된 정수 의 개 수 를 나타 낸다.
그러면 그 중의 한 조건 l, r, c 는 d [r + 1] - d [l] > = c 를 나타 낸다.
그리고 추가 조건 0 < = d [i] - d [i - 1] < = 1 즉 d [i] - d [i - 1] > = 0, d [i - 1] - d [i] > = - 1 구체 적 인 건축 도 보기 코드
방법 2 욕심 + 선분 수
먼저 입력 한 조건 을 오른쪽 단점 에 따라 작은 것 부터 큰 것 까지 정렬 합 니 다.
그리고 어떤 조건 을 처리 할 때 l - > r 사이 에 이미 몇 개의 수가 구조의 집합 에 있 는 지 조회 합 니 다. 만약 에 이 수량 이 요구 하 는 수량 보다 크 거나 같 으 면 처리 하지 않 아 도 됩 니 다.
작 으 면 r - > l 순 으로 선택 하지 않 은 정 수 를 선택 하 세 요.
이렇게 하면 뒤에 선택 한 수 를 최대한 적 게 할 수 있 기 때문에 이곳 의 조회 와 업 데 이 트 는 선분 트 리 최적화 시간 에 코드 를 구체 적 으로 봐 야 합 니 다.
참조 코드 - 궁금 한 점 이 있 으 시 면 아래 에 댓 글 을 남 겨 주시 면 바로 답 해 드 리 겠 습 니 다.
방법 1 코드
#include <iostream>
#include <cstdio>
#include <cstring>
#include <queue>
using namespace std;
const int INF = 1<<29;
const int maxn = 50000 + 10;
int d[maxn], L, R;
bool vis[maxn];
vector<int>E[maxn];
vector<int>W[maxn];
void spfa() {
	memset(vis, 0, sizeof(vis));
	for( int i=L; i<=R+1; i++ ) d[i] = -INF;
	d[R+1] = 0;
	vis[R+1] = 1;
	queue<int>q;
	q.push(R+1);
	while(!q.empty()) {
		int f = q.front(); q.pop(); vis[f] = false;
		//printf("f = %d
", f);
		for( int i=0; i<E[f].size(); i++ ) {
			int v =  E[f][i], w = W[f][i];
			if(d[v] < d[f] + w) {
				d[v] = d[f] + w;
				//printf("v = %d d[v] = %d
", v, d[v]);
				if(vis[v] == false) {
					vis[v] = true;
					q.push(v);
				}
			}
		}
		if(f < R && d[f] > d[f+1]) { //        
			d[f+1] = d[f];
			if(vis[f+1] == false) {
				vis[f+1] = true;
				q.push(f+1);
			}
		}
		if(f > L && d[f] - 1 > d[f-1]) {
			d[f-1] = d[f] - 1;
			if(vis[f-1] == false) {
				vis[f-1] = true;
				q.push(f-1);
			}
		}
	}
}
int main() {
	freopen("in", "r", stdin);
	int n;
	while(scanf("%d", &n) != EOF) {
		L = INF, R = -INF;
		for( int i=0; i<=maxn+2; i++ ) E[i].clear(), W[i].clear();
		for( int i=0; i<n; i++ ) {
			int l, r, c;
			scanf("%d%d%d", &l, &r, &c);
			//E[l] d[r+1] - d[l] >= c        
			E[l].push_back(r+1);
			W[l].push_back(c);
			L = min(L, l);
			R = max(R, r+1);
		}
		int rt = R + 1;
		for( int i=L; i<=R; i++ ) {
			/*if(i != R) {
				E[i].push_back(i+1);
				W[i].push_back(0);
			}
			if(i != L) {
				E[i].push_back(i-1);
				W[i].push_back(-1);
			}*/ //        spfa         
			E[rt].push_back(i);
			W[rt].push_back(0);
		}
		spfa();
		printf("%d
", d[R]);
	}
	return 0;
}방법 2 코드
#include <iostream>
#include <cstdio>
#include <cstring>
#include <queue>
#include <algorithm>
using namespace std;
#define ls (rt<<1)
#define rs ((rt<<1)|1)
#define mid ((l+r)>>1)
const int INF = 1<<29;
const int maxn = 50000 + 10;
int N[maxn*4];
bool all[maxn*4];
struct Node {
	int l, r, c;
	bool operator < (const Node & rhs) const {
		if(r == rhs.r) return c > rhs.c;
		else return r < rhs.r;
	}
}a[maxn];
void pushdown(int rt, int l, int r) {
	if(l == r) return ;
	if(all[rt]) {
		N[ls] = mid-l+1;
		N[rs] = r - mid;
		all[ls] = all[rs] = true;
		all[rt] = false;
	}
}
int query(int rt, int l, int r, int L, int R) {
	pushdown(rt, l, r);
	if(l == L && r == R) return N[rt];
	if(R <= mid) return query(ls, l, mid, L, R);
	else if(L > mid) return query(rs, mid + 1, r, L, R);
	else return query(ls, l, mid, L, mid) + query(rs, mid + 1, r, mid + 1, R);
	N[rt] = N[ls] + N[rs];
}
void update(int rt, int l, int r, int x, int c) {
	pushdown(rt, l, r);
	//printf("%d %d %d x = %d c = %d
", rt, l, r,x, c);
	if(r-l+1-N[rt] == c) {
		N[rt] = r-l+1;
		all[rt] = true;
		return ;
	}
	if(x <= mid) update(ls, l, mid, x, c);
	else {
		int tn = query(1, 0, maxn-10, mid+1, min(r,x));
		tn = min(r,x)-mid-tn;
		//printf("tn = %d
", tn);
		if(tn < c) {
			update(ls, l, mid, x, c - tn);
			update(rs, mid + 1, r, x, tn);
		}
		else update(rs, mid + 1, r, x, c);
	}
	N[rt] = N[ls] + N[rs];
}
int main() {
	freopen("in", "r", stdin);
	int n;
	while(scanf("%d", &n) != EOF) {
		memset(N, 0, sizeof(N));
		memset(all, 0, sizeof(all));
		for( int i=0; i<n; i++ ) {
			int l, r, c;
			scanf("%d%d%d", &a[i].l, &a[i].r, &a[i].c);
		}
		sort(a, a + n);
		for( int i=0; i<n; i++ ) {
			int num = query(1, 0, maxn-10, a[i].l, a[i].r);
			if(num >= a[i].c) continue;
			a[i].c -= num;
			update(1, 0, maxn-10, a[i].r, a[i].c);
		}
		printf("%d
", N[1]);
	}
	return 0;
}이 내용에 흥미가 있습니까?
현재 기사가 여러분의 문제를 해결하지 못하는 경우 AI 엔진은 머신러닝 분석(스마트 모델이 방금 만들어져 부정확한 경우가 있을 수 있음)을 통해 가장 유사한 기사를 추천합니다:
정수 반전Udemy 에서 공부 한 것을 중얼거린다 Chapter3【Integer Reversal】 (예) 문자열로 숫자를 반전 (toString, split, reverse, join) 인수의 수치 (n)가 0보다 위 또는 ...
텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
CC BY-SA 2.5, CC BY-SA 3.0 및 CC BY-SA 4.0에 따라 라이센스가 부여됩니다.