給定乙個數軸上的 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 output6
此題與前幾周做的區間選點有所不同,那一題要求每個區間至少有乙個點,用貪心演算法解決。對於該題,要求第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...