随笔-141  评论-9  文章-3  trackbacks-0

本题是求最大点割集。

首先,构造图。

对于点i,分成u和v两点,并且dist[u][v]=1,dist[v][u]=0;
对于边(i, j), 对于i,根据上述方法分成a1,a2两点,j分成b1,b2; 使dist[b1][a2]=INF,dist[a2][b1]=0; dist[b2][a1]=INF,dist[a1][b2]=0;

然后根据最大流最小割定理,求最大流,使用Dinic。

Dinic的原理是先用bfs构建层次图。判断原点是否在层次图中,如果在,则从原点开始dfs求增广路径,用栈保存路径,求得之后增广之,增广之后有边变为0,则退栈到从原点可达的最远的点。继续dfs求增广路径。如果原点不在层次图,则结束Dinic

重复上述过程。

求得最大流为maxflow

最后求最大点割集,使用cnt作为记号,初始为0,枚举各点,删除之(即删除该点对应的边),然后求当前最大流nowflow,

若nowflow+1 ==maxflow+cnt ;

则cnt ++ ,记录这个点。

/*
ID: lorelei3
TASK: telecow
LANG: C++
*/


#include 
<fstream>
#include 
<memory.h>

using namespace std;

const int MAX = 300;
const int INF = 0x7FFFFFFF;

class Tadj{
public:
    
int cnt;
    
int to[MAX];
    Tadj()
{
        cnt
=0;
    }

    
void ins(int k){
        to[
++cnt]=k;
    }

}
;

class Tqueue{
private:
    
long first, last, size;
    
long list[MAX*MAX];
public:
    Tqueue()
{
        reset();
    }


    
void reset(){
        first
=1, last=0, size=0;
    }


    
void push_back(int k){
        
++size;
        list[
++last]=k;
    }


    
void pop_front(){
        size
--;
        first
++;
    }


    
long front(){
        
return list[first];
    }


    
bool empty(){
        
return size==0;
    }

}
;

class Tstack{
public:
    
int stack[MAX];
    
int top, min, p;

    Tstack()
{
        reset();
    }


    
void reset(){
        top
=0, min=INF;
    }


    
void pop(){
        top
--;
    }


    
void push(int k){
        stack[
++top]=k;
    }

}
;

ifstream fin(
"telecow.in");
ofstream fout(
"telecow.out");

Tqueue Q;
Tstack S;
Tadj adj[MAX];

int s,t,c1,c2,m,n,maxflow;
int level[MAX], set[MAX];
int dist[MAX][MAX], odist[MAX][MAX], flow[MAX][MAX];
bool used[MAX];

inline 
void insert(int u, int v, int cost){
    adj[u].ins(v);
    dist[u][v]
=cost;
}


void input(){
    
int i,u,v;
    fin
>>n>>m>>c1>>c2;

    
if(c1>c2){int c=c1, c1=c2, c2=c;}
    
    
for(i=1; i<=n; ++i){
        u 
= i*2-1;
        v 
= i*2;
        insert(u, v, 
1);
        insert(v, u, 
0);
    }


    
for(i=1; i<=m; ++i){
        fin
>>u>>v;

        
if(u>v)int c=u, u=v, v=c;}

        
int a1=u*2-1, a2=u*2;
        
int b1=v*2-1, b2=v*2;
        insert(a2, b1, INF);
        insert(b1, a2, 
0);
        insert(b2, a1, INF);
        insert(a1, b2, 
0);
    }


    s
=c1*2;
    t
=c2*2-1;
    adj[t].cnt
=0;
    memcpy(odist, dist, 
sizeof(dist));
}


void Dinic_Level(){
    Q.reset();
    memset(used, 
0sizeof(used));
    memset(level, 
0sizeof(level));
    Q.push_back(s);
    
while(!Q.empty()){
        
int u = Q.front();
        Q.pop_front();
        used[u]
=true;
        
for(int i=1; i<=adj[u].cnt; ++i){
            
int v = adj[u].to[i];
            
if(!dist[u][v])    continue;
            
if(used[v] || v==1continue;
            level[v] 
= level[u]+1;
            Q.push_back(v);
        }

    }

}


void Dinic_Argument(){
    S.stack[
0]=s;
    
for(int i=1; i<=S.top; ++i){
        
int u = S.stack[i-1];
        
int v = S.stack[i];
        
if(dist[u][v]<S.min){
            S.min 
= dist[u][v];
            S.p   
= u; 
        }

    }


    
for(int j=S.top; j>=1--j){
        
int u = S.stack[j-1];
        
int v = S.stack[j];
        flow[u][v] 
+= S.min;
        dist[u][v] 
-= S.min;
        dist[v][u] 
+= S.min;
    }

}


bool Dinic_dfs(int u){
    
int outdegree=0;
    
if(u!=t){
        
for(int i=1; i<=adj[u].cnt; ++i){
            
int v = adj[u].to[i];
            
if(level[v]==level[u]+1 && dist[u][v]){
                outdegree
++;
                S.push(v);
                
bool f = Dinic_dfs(v);
                S.pop();
                
if(f && u!=S.p)
                    
return true;
            }
    
        }

        
if(outdegree==0)
            level[u]
=0;
    }
else{
        Dinic_Argument();
        
return true;
    }

    
return false;
}


void Dinic(){
    memset(flow, 
0sizeof(flow));
    
for( ; ; ){
        Dinic_Level();
        
if(level[t]==0)
            
return;
        S.reset();
        Dinic_dfs(s);
    }

}


long max_flow(){
    
long ret = 0;
    
for(int i=1; i<=n*2++i)
        ret 
+= flow[s][i];
    
return ret;
}


void solve(){
    
int cnt = 0;

    Dinic();
    maxflow 
= max_flow();

    
for(int i=1; i<=n; ++i){
        
if(i!=c1 && i!=c2){
            
int u=i*2-1;
            
int v=i*2;
            odist[u][v]
=0;
            memcpy(dist, odist, 
sizeof(odist));
            Dinic();
            
int nowflow = max_flow();
            
if(nowflow+1==maxflow-cnt)
                
set[++cnt]=i;
            
else
                odist[u][v]
=1;
        }

        
if(cnt==maxflow)
            
return;
    }

}


void output(){
    fout
<<maxflow<<endl;

    fout
<<set[1];
    
for(int i=2; i<=maxflow; ++i)
        fout
<<" "<<set[i];
    fout
<<endl;
}


int main(){

    input();

    solve();

    output();

    
return 0;
}
posted on 2011-02-17 13:47 小阮 阅读(691) 评论(0)  编辑 收藏 引用 所属分类: USACO

只有注册用户登录后才能发表评论。
网站导航: 博客园   IT新闻   BlogJava   知识库   博问   管理