2013-09-27 2 views
1

은 내가 dinic의 알고리즘이 문제에 적합 생각 http://www.spoj.com/problems/FASTFLOW/Dinic 알고리즘 구현과 SPOJ 퍼즐

에이 문제를 해결하기 위해 노력하고 있습니다. 그러나 그것은 최악의 경우이 문제에 대해 너무 느린 O (E.V^2) 시간으로 실행됩니다. 다른 알고리즘에 대한 제안이나이 알고리즘의 실행 시간을 개선하기위한 제안?

EDIT : 나는 dinic의 알고리즘을 구현했습니다. 분명히, 그것은 몇 가지 실수를 포함하고 있습니다 ... 누군가가 테스트 케이스를 제공하거나 프로그램의 논리를 디버깅하는 데 도움이 될 수 있습니다.

//#define DEBUG  //comment when you have to disable all debug macros. 
#define NDEBUG //comment when all assert statements have to be disabled. 
#include <iostream> 
#include <cstring> 
#include <sstream> 
#include <cstdlib> 
#include <cstdio> 
#include <cmath> 
#include <vector> 
#include <set> 
#include <map> 
#include <bitset> 
#include <climits> 
#include <ctime> 
#include <algorithm> 
#include <functional> 
#include <stack> 
#include <queue> 
#include <list> 
#include <deque> 
#include <sys/time.h> 
#include <iomanip> 
#include <cstdarg> 
#include <utility> //std::pair 
#include <cassert> 
#define tr(c,i) for(typeof(c.begin()) i = (c).begin(); i != (c).end(); i++) 
#define present(c,x) ((c).find(x) != (c).end()) 
#define all(x) x.begin(), x.end() 
#define pb push_back 
#define mp make_pair 
#define log2(x) (log(x)/log(2)) 
#define ARRAY_SIZE(arr) (1[&arr]-arr)  
#define INDEX(arr,elem)  (lower_bound(all(arr),elem)-arr.begin()) 
#define lld long long int 
#define MOD 1000000007 
#define gcd __gcd 
#define equals(a,b) (a.compareTo(b)==0) //for strings only 
using namespace std; 


#ifdef DEBUG 
#define debug(args...)   {dbg,args; cerr<<endl;} 
#else 
#define debug(args...)    // Just strip off all debug tokens 
#endif 

struct debugger 
{ 
    template<typename T> debugger& operator , (const T& v) 
     {  
      cerr<<v<<" ";  
      return *this;  
     } 

}dbg; 

/**********************************MAIN CODE***************************************************/ 

//runs in O(V^2E) time. 
//might consider using a 1-d array of size V*V for large values of V 

vector<vector<lld> > flow, capacity, level_graph; 
lld V; 
vector<lld> *adj, *level_adj; 

void init(lld v) 
{ 
    adj=new vector<lld>[v+1]; 
    level_adj=new vector<lld>[v+1]; 
    V=v; 
    flow.resize(V+1); 
    capacity.resize(V+1); 
    level_graph.resize(V+1); 
    for(lld i=0;i<=V;i++) 
     flow[i].resize(V+1), capacity[i].resize(V+1), level_graph[i].resize(V+1); 
} 

void add_edge(lld u, lld v, lld uv, lld vu=0) 
{ 
    capacity[u][v]=uv; 
    capacity[v][u]=vu; 
    adj[u].push_back(v); 
    flow[u][v]=uv;    //will store the present capacity. facility for the residual graph 
    flow[v][u]=vu; 
    if(vu) adj[v].push_back(u); 
} 

void update_residual_graph(lld source, lld destination, lld *parent)  //push augment flow in the residual graph and modify the latter. 
{ 
    lld i=destination, aug=LLONG_MAX; 
    while(parent[i]!=-2) 
    { 
     //debug(i); 
     aug=min(aug,flow[parent[i]][i]); 
     i=parent[i]; 
    } 
    i=destination; 
    while(parent[i]!=-2) 
    { 
     flow[parent[i]][i]-=aug; 
     flow[i][parent[i]]=capacity[parent[i]][i]-flow[parent[i]][i]; 
     i=parent[i]; 
    } 
} 

bool DFS(lld source, lld destination) 
{ 
    stack<lld> state; 
    bool visited[V+1], present; 
    lld parent[V+1],t; 
    memset(visited, false, sizeof(visited)); 
    memset(parent, -1, sizeof(parent)); 
    parent[source]=-2; 
    state.push(source); 
    visited[source]=true; 
    while(!state.empty()) 
    { 
     t=state.top(); 
     present=false; 
     for(vector<lld>::iterator it=level_adj[t].begin(); it!=level_adj[t].end();it++) 
     {   
      parent[*it]=t; 
      if(!visited[*it] && level_graph[t][*it]) 
      { 
       present=true; 
       state.push(*it); 
       visited[*it]=true; 
       if(*it==destination) 
        update_residual_graph(source,destination,parent); //update residual graph 
      } 

     } 
     if(!present) 
      state.pop(); 
    } 
    return parent[destination]!=-1; 
} 


bool BFS(lld source, lld destination) 
{ 
    //create level graph usign BFS 
    fill(level_graph.begin(), level_graph.end(), vector<lld>(V+1,-1)); 
    lld i,j; 
    for(i=1;i<=V;i++) 
     level_adj[i].clear(); 


    queue<lld> state; 
    lld level[V+1],t;  //record of minimum distance from source 
    memset(level,-1, sizeof(level)); 
    state.push(source); 
    level[source]=0; 
    while(!state.empty()) 
    { 
     t=state.front(); 
     state.pop(); 
     for(vector<lld>::iterator it=adj[t].begin();it!=adj[t].end();it++) 
     { 
      if((level[*it]==-1 && flow[t][*it]) || (level[*it]==level[t]+1)) 
      { 
       level_graph[t][*it]=flow[t][*it]; 
       level_adj[t].push_back(*it); 
       level[*it]=level[t]+1; 
       state.push(*it); 
      } 
     } 
    } 
    if(level[destination]==-1) 
     return false; 

    //call DFS and update the residual graph 
    return DFS(source,destination); 

} 

lld maximum_flow(lld source, lld destination) 
{ 
    while(BFS(source,destination)); 
    lld max_flow=0; 
    for(vector<lld>::iterator it=adj[source].begin(); it!=adj[source].end(); it++) 
     max_flow+=flow[*it][source]; 
    return max_flow; 
} 

int main() 
{ 
    lld e,u,v,n,c; 
    //cout<<"V:"<<endl; 
    cin>>n>>e; 
    init(n); 

    while(e--)cin>>u>>v>>c, add_edge(u,v,c); 

    cout<<maximum_flow(1,n)<<endl; 

} 

답변

1

Cherkassky에 의해 제안 된 글로벌 레이블 다시 지정 휴리스틱와 푸시 레이블 재 지정 알고리즘 - 골드버그 (모든 m 단계는, 폭 우선 검색과 라벨을 다시 계산) 충분합니다. 휴리스틱 스를 사용한 실제 실행 시간은 최악의 경우 입방 경계보다 훨씬 낫습니다. (갭 재 레이블링도 할 수 있지만 구현하기가 까다 롭고이 애플리케이션에는 필요하지 않을 수도 있습니다.)

+0

그래도 큐빅 시간은 약 10^9의 실행을 의미합니다. 여전히 매우 큽니다. 나는 몇몇 공개 토론을 통해서 수색하고 그들이 dicnic 's algo를 사용했다는 것을 발견했다. 하지만 분명히, push-relable은 dicnic보다 낫습니다. – sudeepdino008

+0

@ sudeepdino008 내가 말했듯이, 문제가되는 설정자가 하드 인스턴스를 만드는 데 방해가되지 않는 한, 실제 성능은 그보다 몇 배 더 좋아질 것입니다. –