1. 程式人生 > >nefu495最長k可重區間集問題【最大權不相交路徑】網路流24題

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;
}


相關推薦

nefu495k區間問題大權相交路徑網路24

本來是應該昨天晚上就寫完的,果然在家的狀態不好==而且以後就應該11點半之前就睡,腦子不靈光寫字都不過腦子還不如睡覺~。~據說今年國賽有5站,留下來問題應該不大,但是能拿什麼獎就不好說了,總之要加油。。方法二沒看懂,最大權不相交路徑太難了,24題裡面只有兩個,還都是4星的=

COGS743k區間問題 大權相交路徑

題目描述 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 21k區間問題

最長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 個正整

網絡2422k線段問題

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 個數所在方格沒有公共邊,且取出的數的總和最大。試設計一個滿足要求的取數演算法。 題解 題目要求不相鄰,可以轉換為最大獨立集,又由於點權不全

網路246 遞增子序列

題目描述 給定正整數序列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\)個數所在方格沒有公共邊,且取出的數的總和最大。試設計一個滿足要求的取數演算法。對於給定的方格棋盤,按照取數要求程式設計找出總和最大的數。 來看看怎麼建圖: 首先我們把