POJ 3469 第一次AC總結(Dinic+多路增廣)

這題是道神題,神就神在,它既能讓你搞懂網絡流及其優化,還給了你很大的優化空間。首先,說一下算法,這題就是一道最小割+簡單構圖的題目,增加兩個節點分別表示兩個CPU,第i個界點與兩個CPU各連接一條,邊權值分別爲Ai、Bi,在後面的輸入中要分別給ab和ba都連接一條權值爲w的邊(注意不要再連反向邊了),然後用你建的圖求最大流即可,這回我用的是Dinic求解。

下面便是優化,這題的優化最有學問,這次我只用了一個優化——多路增廣,由於我的水平低,所以我只能講個大概:多路增廣如其名,即是用一次增廣代替了多次增廣,到一個節點時就一次性地把與其相鄰的所有邊翻出來求增廣的和,如果和爲零,代表它已增廣不出什麼了,把這個點廢掉即可。這樣就省去了冗餘的增廣。再次提醒,某超級大神牛說過,“廢掉”這句話及其重要,一定不能省。

這次我用了4594MS,希望下次能分享到更多優化技巧,使我的程序跑得更快!

附屬代碼(第一次用CSDN,據說CSDN的代碼着色挺專業的,試用一下):

#include <cstdio>
#include <string.h>
#include <queue>
#include <algorithm>
#include <utility>
using namespace std;
const int NMax=20020,MeMax=500000;
struct edge
{
    int num,len;
    edge *next,*rev;
}*S[NMax];
int N,M,L,level[NMax];
edge Me[MeMax];
queue<int> Q;
void Build(int x,int y,int z)
{
    edge *tmp,*tmp2;
    tmp=&Me[L++];
    tmp->num=y;
    tmp->len=z;
    tmp->next=S[x];
    tmp2=&Me[L++];
    tmp2->num=x;
    tmp2->len=0;
    tmp2->next=S[y];
    tmp->rev=tmp2;
    tmp2->rev=tmp;
    S[x]=tmp;
    S[y]=tmp2;
}
void Build2(int x,int y,int z)
{
    edge *tmp,*tmp2;
    tmp=&Me[L++];
    tmp->num=y;
    tmp->len=z;
    tmp->next=S[x];
    tmp->rev=NULL;
    S[x]=tmp;
}
bool CCT()
{
    while(!Q.empty()) Q.pop();
    int tmp;
    memset(level,-1,sizeof(level));
    level[0]=0;
    Q.push(0);
    while(!Q.empty())
    {
        tmp=Q.front();
        Q.pop();
        for(edge *p=S[tmp];p;p=p->next)
        {
            if(p->len && level[p->num]==-1)
            {
                level[p->num]=level[tmp]+1;
                Q.push(p->num);
            }
        }
    }
    return level[N+1]!=-1;
}
int DFS(int a,int Min)
{
    int tmp,tot=0;
    if(a==N+1) return Min;
    for(edge *p=S[a];p;p=p->next)
    {
        if(p->len && level[p->num]==level[a]+1 && tot<Min)
        {
            if(tmp=DFS(p->num,min(p->len,Min-tot)))
            {
                tot+=tmp;
                p->len-=tmp;
                if(p->rev!=NULL) p->rev->len+=tmp;
            }
        }
    }
    if(!tot) level[a]=-1;
    return tot;
}
int main()
{
    int tmp,ans;
    int x,y,z;
    while(scanf("%d%d",&N,&M)!=EOF)
    {
        memset(S,0,sizeof(S));
        ans=0;
        L=0;
        for(int i=1;i<=N;i++)
        {
            scanf("%d%d",&x,&y);
            Build(0,i,x);
            Build(i,N+1,y);
        }
        for(int i=1;i<=M;i++)
        {
            scanf("%d%d%d",&x,&y,&z);
            Build2(x,y,z);
            Build2(y,x,z);
        }
        while(CCT())
        {
            while(tmp=DFS(0,(~0u>>1)))ans+=tmp;
        }
        printf("%d\n",ans);
    }
    return 0;
}


發佈了26 篇原創文章 · 獲贊 1 · 訪問量 1萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章