week8 A 區間選點(差分約束系統)

2021-10-05 03:53:40 字數 1980 閱讀 4072

給定乙個數軸上的 n 個區間,要求在數軸上選取最少的點使得第 i 個區間 [ai, bi] 裡至少有 ci 個點。

使用差分約束系統的解法解決這道題!

input

輸入第一行乙個整數 n 表示區間的個數,接下來的 n 行,每一行兩個用空格隔開的整數 a,b 表示區間的左右端點。1 <= n <=

50000, 0 <= ai <= bi <= 50000 並且 1 <= ci <= bi - ai+1。

output

輸出乙個整數表示最少選取的點的個數

sample input

5

3 7 3

8 10 3

6 8 1

1 3 1

10 11 1

sample output
6
此題與前幾周做的區間選點有所不同,那一題要求每個區間至少有乙個點,用貪心演算法解決。對於該題,要求第i個區間至少有ci個點,學長給出了新的解法——差分約束。

差分約束類似於最短路中的鬆弛操作,對於不等式約束xi-xj<=ck,可以轉化成dis[i]<=dis[j]+w(i,j),移項得dis[j]>=dis[i]+w(i,j)(邊權可正可負可為零),因此可以轉化為圖論中的最短路問題求解。

這道題目首先需要構造不等式組:

記sum[i]表示數軸上[0,i]之間選點的個數

對於第i個區間[ai,bi]需要滿足sum[bi]-sum[ai-1]>=ci

然後根據構造關係,該題是》=,因此跑最長路解決

1.本題邊權可以為負,因此不能用dijkstra解決,這裡用spfa求最長路。

2.關於memset的用法,雖然見到學長這樣用感覺很方便,就用了幾次,但不甚明白原理,出錯了,這裡總結一下。

memset不是對每個int賦值!而是單個位元組逐個copy

如memset(a,0,sizeof(a)) 一般乙個int佔4個位元組,賦值之後是00000000 00000000 00000000 00000000

而memset(a,1,sizeof(a))就變成了00000001 00000001 00000001 00000001乙個int並不是十進位制的「1」

賦值為-1也是可以的,補碼儲存。

若想初始化為乙個很大的數,賦值127就可以了;

賦值128就會初始化為乙個很小的數10000000 10000000 10000000 10000000

大約是-2e9。

#include

#include

#include

#include

using

namespace std;

int n,a,b,c,tot;

const

int maxn=

5e4+

5,size=

1e6+5;

int mina=maxn,maxb=0;

int sum[maxn]

,inq[maxn]

,head[maxn]

;int inf=

-1e9

;//跑最長路inf初始化為最小值

queue<

int> q;

struct edgee[size]

;//注意邊陣列的大小

void

addedge

(int x,

int y,

int w)

void

spfa

(int s)}}

}}void

init()

}int

main()

for(

int i=mina;i<=maxb;i++

)spfa

(mina-1)

;printf

("%d\n"

,sum[maxb]);

return0;

}

week8 A 區間選點 II(差分約束)

一 題目描述 給定乙個數軸上的 n 個區間,要求在數軸上選取最少的點使得第 i 個區間 ai,bi 裡至少有 ci 個點 使用差分約束系統的解法解決這道題 input 輸入第一行乙個整數 n 表示區間的個數,接下來的 n 行,每一行兩個用空格隔開的整數 a,b 表示區間的左右端點。1 n 50000...

Week8 A 區間選點

給定乙個數軸上的 n 個區間,要求在數軸上選取最少的點使得第 i 個區間 ai,bi 裡至少有 ci 個點 input 輸入第一行乙個整數 n 表示區間的個數,接下來的 n 行,每一行兩個用空格隔開的整數 a,b 表示區間的左右端點。1 n 50000,0 ai bi 50000 並且 1 ci b...

week8 A 區間選點

給定乙個數軸上的 n 個區間,要求在數軸上選取最少的點使得第 i 個區間 ai,bi 裡至少有 ci 個點 使用差分約束系統的解法解決這道題 input 輸入第一行乙個整數 n 表示區間的個數,接下來的 n 行,每一行兩個用空格隔開的整數 a,b 表示區間的左右端點。1 n 50000,0 ai b...