zoukankan      html  css  js  c++  java
  • 【[HNOI2006]超级英雄】

    看到楼下有大佬说了网络流做法,来给大佬配个代码

    我们只有我可能都觉得如果不动态加边的话(dinic)可能跑不了这种需要中途退出的二分图匹配

    正当我准备去敲匈牙利的时候突然想到这个题可以二分啊

    于是二分好了

    如果答案是(ans)的话,(ans-1)肯定也满足条件,所以存在单调性,我们就可以二分了

    至于(check)怎么写,我们只对(1)到当前要(check)答案跑一边(dinic)就好了,如果最大的匹配数等于当前答案的话那么这个答案就是合法的

    时间复杂度应该为(O(Vsqrt{n+m} ext{ }logm))

    代码

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<queue>
    #define re register
    #define maxn 5005
    #define INF 9999999
    using namespace std;
    struct node
    {
    	int v,nxt,w,f;
    }e[100005];
    int n,num,m,S,T;
    int d[maxn],vis[maxn],head[maxn];
    int a[maxn],b[maxn];
    int ans=0;
    int tot[maxn];
    inline int read()
    {
    	char c=getchar();
    	int x=0;
    	while(c<'0'||c>'9') c=getchar();
    	while(c>='0'&&c<='9')
    	  x=(x<<3)+(x<<1)+c-48,c=getchar();
    	return x;
    }
    inline void add_edge(int x,int y,int z)
    {
    	e[num].v=y;
    	e[num].nxt=head[x];
    	e[num].w=z;
    	head[x]=num++;
    }
    inline int bfs()
    {
    	queue<int> q;
    	memset(vis,0,sizeof(vis));
    	vis[S]=1;
    	d[S]=0;
    	q.push(S);
    	while(!q.empty())
    	{
    		int k=q.front();
    		q.pop();
    		for(re int i=head[k];i!=-1;i=e[i].nxt)
    		if(!vis[e[i].v])
    		{
    			if(e[i].w<=e[i].f) continue;
    			vis[e[i].v]=1;
    			d[e[i].v]=d[k]+1;
    			q.push(e[i].v);
    		}
    	}
    	return vis[T];
    }
    int dfs(int x,int now)
    {
    	if(x==T||!now) return now;
    	int flow=0,ff;
    	for(re int i=head[x];i!=-1;i=e[i].nxt)
    	if(d[e[i].v]==d[x]+1)
    	{
    		ff=dfs(e[i].v,min(now,e[i].w-e[i].f));
    		if(ff<=0) continue;
    		now-=ff;
    		flow+=ff;
    		e[i].f+=ff;
    		e[i^1].f-=ff;
    		if(!now) break;
    	}
    	return flow;
    }
    inline void did(int x)
    {
    	for(re int i=1;i<=x;i++)
    	{
    		for(re int j=head[i];j!=-1;j=e[j].nxt)
    		if(e[j].f==1&&e[j].v>m) 
    		{
    			tot[i]=e[j].v;
    			break;
    		}
    	}
    }
    inline int check(int x)
    {
    	num=0;
    	memset(head,-1,sizeof(head));
    	memset(e,0,sizeof(e));
    	for(re int i=m+1;i<=m+n;i++) add_edge(i,n+m+1,1),add_edge(n+m+1,i,0);
    	for(re int i=1;i<=x;i++)
    		add_edge(0,i,1),add_edge(i,0,0);
    	for(re int i=1;i<=x;i++)
    	{
    		add_edge(i,a[i],1);
    		add_edge(a[i],i,0);
    		if(a[i]==b[i]) continue;
    		add_edge(i,b[i],1);
    		add_edge(b[i],i,0);
    	}
    	int k=0;
    	while(bfs()) k+=dfs(0,INF);
    	return k==x;
    }
    int main()
    {
    	n=read();
    	m=read();
    	int x,y;
    	S=0,
    	T=n+m+1;
    	memset(head,-1,sizeof(head));
    	for(re int i=1;i<=m;i++)
    		a[i]=read()+1+m,b[i]=read()+1+m;
    	int l=0,r=m;
    	while(l<=r)
    	{
    		int mid=l+r>>1;
    		if(check(mid)) 
    			ans=mid,did(mid),l=mid+1;
    		else r=mid-1;
    	}
    	cout<<ans<<endl;
    	for(re int i=1;i<=ans;i++)
    	printf("%d
    ",tot[i]-1-m);
    	return 0;
    }
    
  • 相关阅读:
    gethostbyname() 用域名或主机名获取IP地址
    recv, recvfrom, recvmsg 从套接口接收一个消息
    献给初学者:谈谈如何学习Linux操作系统
    Linux 文件处理 之扫描目录 DIR
    Python 使用sys模块
    struct dirent和DIR结构体
    职场人必读的文字只花10分钟影响你一辈子!
    信号量与线程互斥锁的区别
    send/sendto/sendmsg函数解析
    互联网常见Open API文档资源
  • 原文地址:https://www.cnblogs.com/asuldb/p/10207799.html
Copyright © 2011-2022 走看看