nefu495最長k可重區間集問題【最大權不相交路徑】網路流24題
本來是應該昨天晚上就寫完的,果然在家的狀態不好==而且以後就應該11點半之前就睡,腦子不靈光寫字都不過腦子還不如睡覺~。~據說今年國賽有5站,留下來問題應該不大,但是能拿什麼獎就不好說了,總之要加油。。方法二沒看懂,最大權不相交路徑太難了,24題裡面只有兩個,還都是4星的==
【問題分析】
最大權不相交路徑問題,可以用最大費用最大流解決。
【建模方法】
方法1
按左端點排序所有區間,把每個區間拆分看做兩個頂點<i.a><i.b>,建立附加源S匯T,以及附加頂點S'。
1、連線S到S'一條容量為K,費用為0的有向邊。
2、從S'到每個<i.a>連線一條容量為1,費用為0的有向邊。
3、從每個<i.b>到T連線一條容量為1,費用為0的有向邊。
4、從每個頂點<i.a>到<i.b>連線一條容量為1,費用為區間長度的有向邊。
5、對於每個區間i,與它右邊的不相交的所有區間j各連一條容量為1,費用為0的有向邊。
求最大費用最大流,最大費用流值就是最長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條權之和最大的不想交路徑,每條路徑為一些不相交的區間序列。由於是最大費用流,兩條路徑之間一定有一些區間相交,可以看做事相交部分重複了2次,
而K條路經就是最多重複了K次。最簡單的想法就是把區間排序後,不相交的區間之間連線一條邊,由於每個區間只能用一次,所以要拆點,點內限制流量。如果我們改變一下思路,
把端點作為網路中的頂點,區間恰恰是特定一些端點之間的邊,這樣建模的複雜度更小。方法1的邊數是O(N^2)的,而方法2的邊數是O(N)的,可以解決更大規模的問題。
/*************
nefu495
2016.1.17
1340k 10ms C++ (g++ 3.4.3)
*************/
#include <iostream>
#include <cstdio>
#include<cstring>
#include <algorithm>
using namespace std;
const int oo=1e9;//無窮大
const int maxm=1111111;//邊的最大數量,為原圖的兩倍
const int maxn=2222;//點的最大數量
int node,src,dest,edge;//node節點數,src源點,dest匯點,edge邊數
int head[maxn],p[maxn],dis[maxn],q[maxn],vis[maxn];//head連結串列頭,p記錄可行流上節點對應的反向邊,dis計算距離
struct edgenode
{
int to;//邊的指向
int flow;//邊的容量
int cost;//邊的費用
int next;//連結串列的下一條邊
} edges[maxm];
void prepare(int _node,int _src,int _dest);
void addedge(int u,int v,int f,int c);
bool spfa();
inline int min(int a,int b)
{
return a<b?a:b;
}
inline void prepare(int _node,int _src,int _dest)
{
node=_node;
src=_src;
dest=_dest;
for (int i=0; i<node; i++)
{
head[i]=-1;
vis[i]=false;
}
edge=0;
}
void addedge(int u,int v,int f,int c)
{
edges[edge].flow=f;
edges[edge].cost=c;
edges[edge].to=v;
edges[edge].next=head[u];
head[u]=edge++;
edges[edge].flow=0;
edges[edge].cost=-c;
edges[edge].to=u;
edges[edge].next=head[v];
head[v]=edge++;
}
bool spfa()
{
int i,u,v,l,r=0,tmp;
for (i=0; i<node; i++) dis[i]=oo;
dis[q[r++]=src]=0;
p[src]=p[dest]=-1;
for (l=0; l!=r; ((++l>=maxn)?l=0:1))
{
for (i=head[u=q[l]],vis[u]=false; i!=-1; i=edges[i].next)
{
if (edges[i].flow&&dis[v=edges[i].to]>(tmp=dis[u]+edges[i].cost))
{
dis[v]=tmp;
p[v]=i^1;
if (vis[v]) continue;
vis[q[r++]=v]=true;
if (r>=maxn) r=0;
}
}
}
return p[dest]>=0;
}
int spfaflow()
{
int i,ret=0,delta;
while (spfa())
{
//按記錄原路返回求流量
for (i=p[dest],delta=oo; i>=0; i=p[edges[i].to])
{
delta=min(delta,edges[i^1].flow);
}
for (int i=p[dest]; i>=0; i=p[edges[i].to])
{
edges[i].flow+=delta;
edges[i^1].flow-=delta;
}
ret+=delta*dis[dest];
}
return ret;
}
int n,k;
struct note
{
int xx,yy;
};
bool cmp(note aa,note bb)
{
if(aa.xx==bb.xx) return aa.yy<bb.yy;
return aa.xx<bb.xx;
}
note num[maxn];
int main()
{
while(~scanf("%d%d",&n,&k))
{
for(int i=1;i<=n;i++)
scanf("%d%d",&num[i].xx,&num[i].yy);
sort(num+1,num+n+1,cmp);
prepare(2*n+3,0,2*n+2);
addedge(src,1,k,0);
for(int i=1;i<=n;i++)
{
addedge(1,i+1,1,0);
addedge(i+n+1,dest,1,0);
addedge(i+1,i+n+1,1,num[i].xx-num[i].yy);
}
for(int i=1;i<=n;i++)
for(int j=i+1;j<=n;j++)
if(num[i].yy<=num[j].xx)//因為是開區間
addedge(i+n+1,j+1,1,0);
printf("%d\n",-spfaflow());
}
return 0;
}
相關推薦
nefu495最長k可重區間集問題【最大權不相交路徑】網路流24題
本來是應該昨天晚上就寫完的,果然在家的狀態不好==而且以後就應該11點半之前就睡,腦子不靈光寫字都不過腦子還不如睡覺~。~據說今年國賽有5站,留下來問題應該不大,但是能拿什麼獎就不好說了,總之要加油。。方法二沒看懂,最大權不相交路徑太難了,24題裡面只有兩個,還都是4星的=
【COGS743】最長k可重區間集問題 最大權不相交路徑
題目描述 Description 給定實直線L 上n 個開區間組成的集合I,和一個正整數k,試設計一個演算法,從開區 間集合I 中選取出開區間集合S屬於I,使得在實直線L 的任何一點x,S 中包含點x 的開區間 個數不超過k,且sum(| z |) z屬於
最長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,然
loj6005「網路流 24 題」最長遞增子序列(dp+最大流)
首先第一問就是dp求就好啦,寫了nlogn的。 現在我們已經有了dp[i],表示以第i個數結尾的lis是多長。考慮如何建圖實現第二問的限制,把每個點拆成兩點,建邊,容量為1,這樣就滿足了每個點最多被經過一次,然後源點向所有dp[i]為1的點建邊,容量為1,所有
【網路流 24 題】方格取數(二分圖的最大點權獨立集)
題意 在一個有 m×nm \times nm×n個方格的棋盤中,每個方格中有一個正整數。 現要從方格中取數,使任意 222 個數所在方格沒有公共邊,且取出的數的總和最大。試設計一個滿足要求的取數演算法。 題解 題目要求不相鄰,可以轉換為最大獨立集,又由於點權不全
網路流24題6 最長遞增子序列
題目描述 給定正整數序列x1,…,xn 。 (1)計算其最長遞增子序列的長度s。 (2)計算從給定的序列中最多可取出多少個長度為s的遞增子序列。 (3)如果允許在取出的序列中多次使用x1和xn,則從給定序列中最多可取出多少個長度為s的遞增子序列。
【網絡流24題】數字梯形問題(費用流)(最大權不相交路徑)
output 提示 正整數 cti 移動 block 完全 amp 方向 1913 數字梯形問題 時間限制: 2 s 空間限制: 256000 KB 題目等級 : 大師 Master
dinic求解二分圖最大匹配&&網路流24題之飛行員配對方案問題
在二分圖的基礎上增加源S和匯T。1、S向X集合中每個頂點連一條容量為1的有向邊。2、Y集合中每個頂點向T連一條容量為1的有向邊。3、XY集合之間的邊都設為從A集合中的點到B集合之中的點,容量為1的有向邊。 求網路最大流,流量就是匹配數,所有滿流邊是一組可行解。 所以就解決了。 飛行員配對
洛谷 P2765 魔術球問題(網路流24題-最大流)
題意:中文題(lrj黑書上好像有這道題) 思路:這個題的建圖還真的是挺有意思的,我們把一個球拆成2個點a,b。 然後讓a點連S點,b點連T點,如果有兩個數的加和為平方數,那我們就用第一個數的a點連向第二個數的b點,這樣就有一條流直接流向匯點T 程式碼:(順便get了怎麼列印路徑,賦學習傳送門) #
【網路流24題】最小路徑覆蓋問題-二分圖匹配/最大流
傳送門:luogu P2764 最小路徑覆蓋問題 題解 結論: D A G
[網路流24題-12]最小路徑覆蓋問題
最小路徑覆蓋問題 有點蠢。。。結論題。。。(還是魔術球問題的一個部分) DAG最小路徑覆蓋直接拆點建二分圖然後頂點數-最大匹配就可以了。。。 其他相關結論見魔術球問題(大霧) 大體相當於“找出路”。 蠢蠢的還RE了一發QAQ 附程式碼。 #include<cst
網路流24題之方格取數問題 二分圖+最小割
原題連結 題目大意 在一個有\(n\times m\)個方格的棋盤中,每個方格中有一個正整數。現要從方格中取數,使任意\(2\)個數所在方格沒有公共邊,且取出的數的總和最大。試設計一個滿足要求的取數演算法。對於給定的方格棋盤,按照取數要求程式設計找出總和最大的數。 來看看怎麼建圖: 首先我們把