poj 1815 Friendship 求字典序最小的最小割

题意:

拆点后是求无向图字典序最小的最小割。

分析:

       设有边e(u,v),则下面三点等价:

       1:e可以作为割边(最小割集不唯一)。

       2:去掉e后最小割值变小。

       3:残量网络中不存在u到v的增广路。

       所以从编号小的边开始,判断该边可不可能是割边,如果可能,把这条边去了,退流。如果不可能,保持原状,处理下一条边。

代码:

 

//poj 1815
//sep9
#include <iostream>
#include <queue>
using namespace std;
const int MAXN=512;
const int MAXM=20000;

struct Edge
{
	int v,nxt,f;
}e[MAXM];
queue<int> que;
int src,sink;
int g[MAXN],dist[MAXN];
int nume;
bool vis[MAXN];

int N,S,T,n,s,t,mark[MAXN];

void addedge(int u,int v,int c)
{
    e[++nume].v=v;e[nume].f=c;e[nume].nxt=g[u];g[u]=nume;      
    e[++nume].v=u;e[nume].f=0;e[nume].nxt=g[v];g[v]=nume;  
}

void init()      
{      
    memset(g,0,sizeof(g));        
    nume=1;      
}      
      
int bfs()      
{      
    while(!que.empty()) que.pop();      
    memset(dist,0,sizeof(dist));      
    memset(vis,0,sizeof(vis));      
    vis[src]=true;      
    que.push(src);        
    while(!que.empty()){      
        int u=que.front();que.pop();      
        for(int i=g[u];i;i=e[i].nxt)      
            if(e[i].f>0&&!vis[e[i].v]){      
                que.push(e[i].v);      
                dist[e[i].v]=dist[u]+1;      
                vis[e[i].v]=true;       
                if(e[i].v==sink)      
                    return 1;      
            }      
    }      
    return 0;      
}  

int dfs(int u,int delta)      
{      
    if(u==sink)      
        return delta;      
    int ret=0;      
    for(int i=g[u];ret<delta&&i;i=e[i].nxt)      
        if(e[i].f>0&&dist[e[i].v]==dist[u]+1){      
            int dd=dfs(e[i].v,min(e[i].f,delta-ret));      
            if(dd>0){      
                e[i].f-=dd;      
                e[i^1].f+=dd;      
                ret+=dd;      
            }      
            else      
                dist[e[i].v]=-1;      
        }         
    return ret;      
}         

int dinic()      
{      
    int ret=0;      
    while(bfs()==1)      
        ret+=dfs(src,INT_MAX);      
    return ret;       
}   

int extend(int x,int a)
{
	if(x==2*a)
		return 1;
	vis[x]=1;
	for(int i=g[x];i;i=e[i].nxt)
		if(e[i].f&&!vis[e[i].v]&&extend(e[i].v,a))
			return 1;	
	return 0;
}

int extend(int a)
{
	memset(vis,0,sizeof(vis));
	return extend(2*a-1,a);
}

int dfs1(int x,int t)
{
	if(x==t) return 1;
	vis[x]=1;
	for(int i=g[x];i;i=e[i].nxt)
		if(e[i].f&&!vis[e[i].v]&&dfs1(e[i].v,t)){
			--e[i].f;
			++e[i^1].f;
			return 1;
		}
	return 0;		
}
void redo(int a)
{
	memset(vis,0,sizeof(vis));
	dfs1(sink,2*a);
	e[mark[a]].f=0,e[mark[a]^1].f=0;
	memset(vis,0,sizeof(vis));
	dfs1(2*a-1,src); 
}

int main()
{
	init();
	scanf("%d%d%d",&n,&s,&t);
	for(int i=1;i<=n;++i){
		mark[i]=nume+1;
		if(i!=s&&i!=t)
			addedge(2*i-1,2*i,1);
		else
			addedge(2*i-1,2*i,INT_MAX);
	}
	int x;
	for(int i=1;i<=n;++i)
		for(int j=1;j<=n;++j){
			scanf("%x",&x);
			if(x&&i!=j)
				addedge(2*i,2*j-1,INT_MAX);
		}
	src=2*s-1,sink=2*t;
	int ret=dinic();
	if(ret==INT_MAX) puts("NO ANSWER!");
	else{
		printf("%d\n",ret);
		for(int i=1;i<=n;++i)
			if(i!=s&&i!=t)
				if(!e[mark[i]].f&&!extend(i)){
					printf("%d ",i);
					redo(i);
				}
	}
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值