POJ 1201 Intervals 差分约束,最短路,RE会报TLE 难度:1 差分约束背景知识需联想证明

题目

http://poj.org/problem?id=1201

题意

给你n个整数区间(5e4数量级),要求给出一个最小的整数集合,这个整数集合至少与第i个区间有ci个重合整数

思路

很裸的差分约束,若令dp[w]为在[0, w]中取多少个整数,明显dp[bi] - dp[ai-1] = ci。那么现在还缺乏能够灵活调控具体数字的其他约束。这里选择了0<=dp[i]-dp[i - 1] <=1。
从一个非可行解出发,比如dp[w], w=[1, mx],这里mx是最大的区间右端点,那么明显求满足约束的最大对偶解就能确保其可行,对应可行解的最小解。

感想

  1. 这道题RE会报TLE!之前把first[MAXL]写成了first[MAXN],怎么也找不出为什么别人的能过自己的TLE
  2. 一开始想成了01整数规划。看来要多理解差分约束相关的思路

Code

3596K 329MS

#include <iostream>
#include <cstring>
#include <cstdio>
#include <queue>
#include <assert.h>
using namespace std;
const int MAXN = 5e4;
const int MAXL = 5e4 + 2;
const int MAXE = MAXL * 3;
int n, mx, mn;
int a[MAXN];
int b[MAXN];
int c[MAXN];
int e;
int first[MAXL];
int nxt[MAXE];
int to[MAXE];
int cost[MAXE];
int dp[MAXL];
bool used[MAXL];
int que[MAXL];

void addEdge(int f, int t, int c) {
	nxt[e] = first[f];
	to[e] = t;
	cost[e] = c;
	first[f] = e++;
}

int main() {
	freopen("C:\Users\Iris\source\repos\Project1\input.txt", "r", stdin);
	freopen("C:\Users\Iris\source\repos\Project1\out.txt", "w", stdout);
	e = 0;
	memset(first, -1, sizeof first);
	mn = MAXL;
	scanf("%d", &n);
	for (int i = 0; i < n; i++){
		scanf("%d%d%d", a + i, b + i, c + i);
		a[i] ++;
		b[i] ++;
		mx = max(mx, b[i]);
		mn = min(mn, a[i] - 1);
		if(c[i] > 0)addEdge(b[i], a[i] - 1, c[i]);
	}
	for (int i = mn + 1; i <= mx; i++) {
		addEdge(i - 1, i, -1);
		addEdge(i, i - 1, 0);
		dp[i] = -1e9;
	}
	int quewnum = 0;
	int quernum = 0;
	dp[mx] = 0;
	used[mx] = true;
	que[(quewnum++) % MAXL] = mx;
	while (quernum < quewnum) {
		int f = que[(quernum++) % MAXL];
		used[f] = false;
		for (int p = first[f]; p != -1; p = nxt[p]) {
			int t = to[p];
			int c = cost[p];
			if (dp[t] < dp[f] + c) {
				//printf("%d(dp: %d)->%d(dp:%d/%d) %d
", f, dp[f], t, dp[t], dp[f] + c, c);
				dp[t] = dp[f] + c;
				if (!used[t]) {
					que[(quewnum++) % MAXL] = t;
					used[t] = true;
				}
			}
		}
	}
	printf("%d
", dp[mn]);
	return 0;
}

原文地址:https://www.cnblogs.com/xuesu/p/14368371.html