【COGS743】最長k可重區間集問題 最大權不相交路徑
題目描述 Description
給定實直線L 上n 個開區間組成的集合I,和一個正整數k,試設計一個演算法,從開區
間集合I 中選取出開區間集合S屬於I,使得在實直線L 的任何一點x,S 中包含點x 的開區間
個數不超過k,且sum(| z |) z屬於S,達到最大。這樣的集合S稱為開區間集合I的最長k可重區間集。
sum(| z |) z屬於S稱為最長k可重區間集的長度。
對於給定的開區間集合I和正整數k,計算開區間集合I的最長k可重區間集的長度。
輸入描述 Input Description
第1 行有2 個正整數n和k,分別表示開區間的
個數和開區間的可重迭數。接下來的n行,每行有2個整數,表示開區間的左右端點座標。
輸出描述 Output Description
將計算出的最長k可重區間集的長度輸出
樣例輸入 Sample Input
4 2
1 7
6 8
7 10
9 13
樣例輸出 Sample Output
15
資料範圍及提示 Data Size & Hint
若把每個線段看做點,一組不相交的線段集合就可以看做路徑。這樣問題就轉化為選k條路徑使得權值和最大,並且路徑不能重疊(一個線段只能選一次)。
方法1
按左端點排序所有區間,把每個區間拆分看做兩個頂點
1、連線S到S’一條容量為K,費用為0的有向邊。
2、從S’到每個
3、從每個
4、從每個頂點
5、對於每個區間i,與它右邊的不相交的所有區間j各連一條容量為1,費用為0的有向邊。
求最大費用最大流,最大費用流值就是最長k可重區間集的長度。
這種方法相對與方法2來說比較好想。拆點(計算選邊的價值),容量限制(k個,以及不相交)。
方法2
離散化所有區間的端點,把每個端點看做一個頂點,建立附加源S匯T。
1、從S到頂點1(最左邊頂點)連線一條容量為K,費用為0的有向邊。
2、從頂點2N(最右邊頂點)到T連線一條容量為K,費用為0的有向邊。
3、從頂點i到頂點i+1(i+1<=2N),連線一條容量為無窮大,費用為0的有向邊。
4、對於每個區間[a,b],從a對應的頂點i到b對應的頂點j連線一條容量為1,費用為區間長度的有向邊。
求最大費用最大流,最大費用流值就是最長k可重區間集的長度。
轉換思路:端點為點。同樣是限制流量。而這次目標針對了【每個點至多出現k次】,而區間則成了一段有價值的點,所以可以端點之間連邊來表示。並且這個做法邊數更少,更優。
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<iostream>
#include<queue>
using namespace std;
const int INF = 1000000010;
const int SZ = 1000010;
int head[SZ],nxt[SZ],tot = 1;
struct edge{
int f,t,d,c;
}l[SZ];
void build(int f,int t,int d,int c)
{
l[++ tot].t = t;
l[tot].d = d;
l[tot].f = f;
l[tot].c = c;
nxt[tot] = head[f];
head[f] = tot;
}
void insert(int f,int t,int d,int c)
{
build(f,t,d,c); build(t,f,0,-c);
}
int dist[SZ];
deque<int> q;
bool use[SZ];
int pre[SZ];
bool spfa(int s,int e)
{
use[s] = 1;
q.push_front(s);
for(int i = 0;i <= 100000;i ++)
dist[i] = -INF;
dist[s] = 0;
while(q.size())
{
int u = q.front(); q.pop_front();
use[u] = 0;
for(int i = head[u];i;i = nxt[i])
{
int v = l[i].t;
if(l[i].d && dist[v] < dist[u] + l[i].c)
{
dist[v] = dist[u] + l[i].c;
pre[v] = i;
if(!use[v])
{
use[v] = 1;
if(q.empty()) q.push_front(v);
else if(dist[q.front()] > dist[v])
q.push_front(v);
else
q.push_back(v);
}
}
}
}
if(dist[e] == -INF) return false;
return true;
}
int dfs(int s,int e)
{
int x = INF,ans = 0;
for(int i = pre[e];i;i = pre[l[i].f])
x = min(x,l[i].d);
for(int i = pre[e];i;i = pre[l[i].f])
ans += x * l[i].c,l[i].d -= x,l[i ^ 1].d += x;
return ans;
}
int ek(int s,int e)
{
int ans = 0;
while(spfa(s,e)) ans += dfs(s,e);
return ans;
}
struct haha{
int l,r;
}seg[SZ];
bool cmp(haha a,haha b)
{
return a.l < b.l;
}
int main()
{
freopen("interv.in","r",stdin);
freopen("interv.out","w",stdout);
int n,k;
scanf("%d%d",&n,&k);
for(int i = 1;i <= n;i ++)
scanf("%d%d",&seg[i].l,&seg[i].r);
sort(seg + 1,seg + 1 + n,cmp);
int S = n * 2 + 1,S1 = n * 2 + 2,T = n * 2 + 3;
insert(S,S1,k,0);
for(int i = 1;i <= n;i ++)
insert(S1,i,1,0),insert(i + n,T,1,0),insert(i,i + n,1,seg[i].r - seg[i].l);
for(int i = 1;i <= n;i ++)
{
for(int j = i + 1;j <= n;j ++)
{
if(seg[i].r <= seg[j].l)
{
insert(i + n,j,1,0);
}
}
}
printf("%d\n",ek(S,T));
return 0;
}
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<iostream>
#include<queue>
using namespace std;
const int INF = 1000000010;
const int SZ = 1000010;
int head[SZ],nxt[SZ],tot = 1;
struct edge{
int f,t,d,c;
}l[SZ];
void build(int f,int t,int d,int c)
{
l[++ tot].t = t;
l[tot].d = d;
l[tot].f = f;
l[tot].c = c;
nxt[tot] = head[f];
head[f] = tot;
}
void insert(int f,int t,int d,int c)
{
build(f,t,d,c); build(t,f,0,-c);
}
int dist[SZ];
deque<int> q;
bool use[SZ];
int pre[SZ];
bool spfa(int s,int e)
{
use[s] = 1;
q.push_front(s);
for(int i = 0;i <= 100000;i ++)
dist[i] = -INF;
dist[s] = 0;
while(q.size())
{
int u = q.front(); q.pop_front();
use[u] = 0;
for(int i = head[u];i;i = nxt[i])
{
int v = l[i].t;
if(l[i].d && dist[v] < dist[u] + l[i].c)
{
dist[v] = dist[u] + l[i].c;
pre[v] = i;
if(!use[v])
{
use[v] = 1;
if(q.empty()) q.push_front(v);
else if(dist[q.front()] > dist[v])
q.push_front(v);
else
q.push_back(v);
}
}
}
}
if(dist[e] == -INF) return false;
return true;
}
int dfs(int s,int e)
{
int x = INF,ans = 0;
for(int i = pre[e];i;i = pre[l[i].f])
x = min(x,l[i].d);
for(int i = pre[e];i;i = pre[l[i].f])
ans += x * l[i].c,l[i].d -= x,l[i ^ 1].d += x;
return ans;
}
int ek(int s,int e)
{
int ans = 0;
while(spfa(s,e)) ans += dfs(s,e);
return ans;
}
struct haha{
int l,r;
}seg[SZ];
int lsh[SZ];
int main()
{
freopen("interv.in","r",stdin);
freopen("interv.out","w",stdout);
int n,k;
scanf("%d%d",&n,&k);
for(int i = 1;i <= n;i ++)
{
scanf("%d%d",&seg[i].l,&seg[i].r);
lsh[++ lsh[0]] = seg[i].l;
lsh[++ lsh[0]] = seg[i].r;
}
sort(lsh + 1,lsh + 1 + lsh[0]);
int m = unique(lsh + 1,lsh + 1 + lsh[0]) - lsh - 1;
int S = m + 1,T = m + 2;
insert(S,1,k,0); insert(m,T,k,0);
for(int i = 1;i < m;i ++)
insert(i,i + 1,INF,0);
for(int i = 1;i <= n;i ++)
{
int x = lower_bound(lsh + 1,lsh + 1 + m,seg[i].l) - lsh;
int y = lower_bound(lsh + 1,lsh + 1 + m,seg[i].r) - lsh;
insert(x,y,1,seg[i].r - seg[i].l);
}
printf("%d\n",ek(S,T));
return 0;
}
相關推薦
【COGS743】最長k可重區間集問題 最大權不相交路徑
題目描述 Description 給定實直線L 上n 個開區間組成的集合I,和一個正整數k,試設計一個演算法,從開區 間集合I 中選取出開區間集合S屬於I,使得在實直線L 的任何一點x,S 中包含點x 的開區間 個數不超過k,且sum(| z |) z屬於
nefu495最長k可重區間集問題【最大權不相交路徑】網路流24題
本來是應該昨天晚上就寫完的,果然在家的狀態不好==而且以後就應該11點半之前就睡,腦子不靈光寫字都不過腦子還不如睡覺~。~據說今年國賽有5站,留下來問題應該不大,但是能拿什麼獎就不好說了,總之要加油。。方法二沒看懂,最大權不相交路徑太難了,24題裡面只有兩個,還都是4星的=
最長k可重區間集問題
ace blog register 一個 inf for wap ans string 最長k可重區間集問題 題目鏈接 https://www.luogu.org/problemnew/show/3358 做法 所有點向下一個點連容量為k費用為0的邊 l和r連容量為1費用為
「網絡流24題」「LuoguP3358」 最長k可重區間集問題
取反 spa 區間 out freopen clu 內存 ted sizeof 題目描述 對於給定的開區間集合 I 和正整數 k,計算開區間集合 I 的最長 k可重區間集的長度。 輸入輸出格式 輸入格式: 的第 1 行有 2 個正整數 n和 k,分別表示開區
網路流24題 21最長k可重區間集問題
最長k可重區間集問題 Time Limit 1000ms Memory Limit 65536K description 給定實直線L 上n 個開區間組成的集合I,和一個正整數k,試設計一個演算法,從開區間集合I 中選取出開區間集合S屬
「Luogu3358」 最長k可重區間集問題
n+1 fin getc std 線段 front 起點 typename cst 「Luogu3358」 最長k可重區間集問題 problem Solution 最大費用最大流模型。 約定:下文采用格式\((u,v,f,c)\)表示以\(u\)為起點,\(v\)為終點,\
網絡流 P3358 最長k可重區間集問題
size 分享圖片 cos 離散化 復制 正向 ron \n 離散 P3358 最長k可重區間集問題 題目描述 對於給定的開區間集合 I 和正整數 k,計算開區間集合 I 的最長 k可重區間集的長度。 輸入輸出格式 輸入格式: 的第 1 行有 2 個正整
【網絡流24題22】最長k可重線段集問題
ans http ret 網絡流24題 math 離散化 cpp main 擴大 題面戳我 題面自己去看(我懶得搞這些markdown) 成功成為繼ppl之後第二個在洛谷上AC這道題的ID。ppl把這題的AC率從0%提升到了2.5%,提升了無數倍,ppl果然是墜強的!這裏先
洛谷 P3357 最長k可重線段集問題【最大流】
img 分享圖片 math sqrt 最長 .html getchar -m wap pre:http://www.cnblogs.com/lokiii/p/8435499.html 和最長k可重區間集問題差不多,也就是價值的計算方法不一樣,但是註意這裏可能會有x0==x1
「Luogu3357」 最長k可重線段集問題
lower span str getc ios iostream .html problem esp 「Luogu3357」 最長k可重線段集問題 problem Solution 與「Luogu3357」 最長k可重區間集問題類似,但此題需要考慮斜率不存在的線段 我們將每
bzoj1061(k可重區間集)
然而還是不能夠很好地理解線性規劃,因此再看了一下發現其實是k可重區間集問題。。 那麼建圖方向就有了。。然而這個題比較特殊,只有下界沒有上界,想跑上下界也不行了。。 因此可以把容量取反,下界就變成上界了。。然後由於網路流只接受正數流,因此要把取反之後的容量加上inf,然
【網絡流24題】數字梯形問題(費用流)(最大權不相交路徑)
output 提示 正整數 cti 移動 block 完全 amp 方向 1913 數字梯形問題 時間限制: 2 s 空間限制: 256000 KB 題目等級 : 大師 Master
【軟體開發底層知識修煉】九 連結器-可重定位檔案與可執行檔案
上幾篇文章學習了Binutils輔助工具裡面的幾個實用的工具,那些工具對於以後的學習都是非常有幫助的,尤其是C語、C++語言的學習以及除錯是非常有幫助的。點選連結檢視上一篇文章:點選檢視 本篇文章開始一個新的知識的學習,連結器的學習。學習完連結器的系列文章,我們將全面瞭解連結器的工作
【ShawnZhang】帶你看藍橋杯——演算法提高 最長單詞
該題通過本提示通過列舉演算法解決,恕本人愚鈍,不太清楚,就用了自己的方法,程式碼附後 遇到的幾個問題,如果使用String s=in.next()將無法儲存空格後的內容,如I am a student,通過這個函式只能儲存第一個單詞 I(單詞意思:我,大寫的i),所以我
【部分轉載】:【lower_bound、upperbound講解、二分查詢、最長上升子序列(LIS)、最長下降子序列模版】
二分 lower_bound lower_bound()在一個區間內進行二分查詢,返回第一個大於等於目標值的位置(地址) upper_bound upper_bound()與lower_bound()的主要區別在於前者返回第一個大於目標值的位置 int lowerBound(int x){ i
【BZOJ3698】XWW的難題 有上下界的最大流
head 上界 需要 ace min 1.2 3.6 queue 取整 【BZOJ3698】XWW的難題 Description XWW是個影響力很大的人,他有很多的追隨者。這些追隨者都想要加入XWW教成為XWW的教徒。但是這並不容易,需要通過XWW的考核。XWW給
【BZOJ4950】lydsy七月月賽 C 二分圖最大匹配
for 但是 需要 com 成了 strong div mic printf 【BZOJ4950】lydsy七月月賽 C 題面 題解:比較直接的想法就是:每行,每列的最大值都留下,剩下的格子都變成1。但是如果一個格子既是行的最大值又是列的最大值,那麽我們只需要把它留下即
MT【16】利用柯西不等式求三角的最大值
技術分享 com style img 不等式 bsp nbsp png 均值 評:此題也可以設$1+cos\theta=t$,平方後變成$t$的單變量利用均值去做. 柯西平衡系數法其實就是待定系數法,利用等號取到的條件。MT【16】利用柯西不等式求三角的最大值
MT【61】含參數二次函數最大最小值
tco pla 最大 back inline 我們 最小 但是 alt 評:此類題目在高考中作為壓軸題也曾考過,一般通性通法都如上面的做法,但是我們如果可以站在包絡的角度,很多問題將變得很清晰:MT【61】含參數二次函數最大最小值
【經驗】電腦長時間不關機導致的無法開機問題
啟動菜單 但是 can win7 一段 分鐘 硬盤 size 開機 本來不打算寫電腦掛掉這種問題的記錄,但是我這個問題比較特殊還遇到兩次,直接送電腦店可能會說主板掛了,返廠檢修之類的,對於緊急用電腦的人來說是不可接受的,其實分分鐘就可以解決。 1.環境:用了7年的宏碁475