• 网络流


    蜥蜴

    思路

    题目限制了点的流量,我们可以把每一个点拆开,连一条上限为这个点的上限的边,对于每一个有蜥蜴的点,向超级原点建一条权值为1边,对于每一个可以跳出范围的点,建一个向超级汇点权值为inf的边,然后跑最大流就可以求出可以逃离的最大值了(需要注意的是d不是曼哈顿距离)

    code

    #include<bits/stdc++.h>
    #define int ll
    #define db double
    #define ll long long
    #define re register 
    #define gc getchar()
    #define getch while(ch<'0'||ch>'9'){if(ch=='-')f=-f;ch=gc;}
    #define getnu while(ch>='0'&&ch<='9'){s=(s<<1)+(s<<3)+ch-'0';ch=gc;}
    using namespace std;
    inline int read(){int s=0,f=1;char ch=gc;getch;getnu;return s*f;}
    const int maxn=300+2,maxm=2e5+10;
    const int inf=0x7f7f7f7f7f7f7f7f;
    const db eps=1e-5;
    int ver[maxm],nxt[maxm],edge[maxm],head[maxn*maxn*2],tot=1;
    int a[maxn][maxn];
    char ch[maxn];
    void add(int x,int y,int z){ver[++tot]=y,nxt[tot]=head[x],edge[tot]=z,head[x]=tot;}
    int r,c,d,s,t,cnt,n;
    int getid(int x,int y){return (x-1)*c+y;}
    db getdis(int x1,int y1,int x2,int y2){
    	return sqrt((db)(x2-x1)*(x2-x1)+(y2-y1)*(y2-y1));
    }
    void ADD(int x,int y){
    	for(int i=max(1ll,x-d);i<=min(r,x+d);i++)for(int j=max(1ll,y-d);j<=min(c,x+d);j++)
    		if(getdis(i,j,x,y)<=d)add(getid(x,y)+r*c,getid(i,j),inf),add(getid(i,j),getid(x,y)+r*c,0);
    }
    bool jud(int x,int y){return ((x+d>r)||(x-d<1)||(y+d>c)||(y-d<1));}
    int cur[maxn*maxn*2],dis[maxn*maxn*2];
    bool bfs(){
    	for(int i=1;i<=n;i++)dis[i]=-1;
    	queue<int>q;q.push(s);dis[s]=0;
    	while(!q.empty()){
    		int u=q.front();q.pop();
    		for(int i=head[u];i;i=nxt[i]){
    			int v=ver[i];
    			if(dis[v]==-1 && edge[i]>0)dis[v]=dis[u]+1,q.push(v);
    		}
    	}
    	return (dis[t]!=-1);
    }
    int dfs(int u,int flow){
    	if(u==t)return flow;
    	int _flow=0,__flow;
    	for(int& i=cur[u];i;i=nxt[i]){
    		int v=ver[i];
    		if(dis[v]==dis[u]+1 && edge[i]>0){
    			__flow=dfs(v,min(flow,edge[i]));
    			flow-=__flow;
    			edge[i]-=__flow;
    			_flow+=__flow;
    			edge[i^1]+=__flow;
    			if(!flow)break;
    		}
    	}
    	if(!_flow)dis[u]=-1;
    	return _flow;
    }
    void dinic(){
    	int max_flow=0;
    	while(bfs()){
    		for(int i=1;i<=n;i++)cur[i]=head[i];
    		max_flow+=dfs(s,inf);
    	}
    	printf("%lld
    ",cnt-max_flow);
    }
    signed main(){
    	r=read(),c=read(),d=read();
    	s=r*c*2+1,t=r*c*2+2;n=r*c*2+2;
    	for(int i=1;i<=r;i++)for(int j=1;j<=c;j++){
    		scanf("%1lld",&a[i][j]);add(getid(i,j),getid(i,j)+r*c,a[i][j]);add(getid(i,j)+r*c,getid(i,j),0);
    		if(jud(i,j))add(getid(i,j)+r*c,t,inf),add(t,getid(i,j)+r*c,0);
    	}
    	for(int i=1;i<=r;i++)for(int j=1;j<=c;j++)for(int k=1;k<=r;k++)for(int l=1;l<=c;l++)if(getdis(i,j,k,l)-d<=eps){
    		add(getid(i,j)+r*c,getid(k,l),inf);
    		add(getid(k,l),getid(i,j)+r*c,0);
    		add(getid(k,l)+r*c,getid(i,j),inf);
    		add(getid(i,j),getid(k,l)+r*c,0);
    	}
    	for(int i=1;i<=r;i++){
    		scanf("%s",ch+1);
    		for(int j=1;j<=c;j++)if(ch[j]=='L')add(s,getid(i,j),1),add(getid(i,j),s,0),cnt++;
    	}
    	dinic();
    	return 0;
    }
    
    
    

    星际战争

    思路

    容易现题目中含有单调性,即花 (i) (s)可以消灭所有机器人,那么花(i+1) (s)一定也可以消灭所有的机器人,所以我们可以二分消灭所有机器人的时间,可以注意到,每一个机器人有自己的装甲值,装价值在0或0以下之后就不能再攻击,那么我们肯定会选择刚好把这个机器人的装甲值降为0,所以就相当于这个机器人最多受到该装甲值大小的伤害,和上一题一样处理,拆点,建一条大小为装甲值的边,对于每一个机器人,建一条和超级原点连接的权值可变的边,然后每次二分时间,跑最大流时,加入权值就可以了

    code

    #include<bits/stdc++.h>
    #define ll long long
    #define re register 
    #define db long double
    #define int ll
    #define gc getchar()
    #define getch while(ch<'0'||ch>'9'){if(ch=='-')f=-f;ch=gc;}
    #define getnu while(ch>='0'&&ch<='9'){s=(s<<1)+(s<<3)+ch-'0';ch=gc;}
    using namespace std;
    inline int read(){int s=0,f=1;char ch=gc;getch;getnu;return s*f;}
    const int maxn=51*4,maxm=5000+10;
    const int inf=0x7f7f7f7f7f7f7f7f;
    const db eps=1e-7;
    int head[maxn],nxt[maxm<<1],ver[maxm<<1],tot=1;
    db _edge[maxm<<1];
    db edge[maxm<<1];
    void add(int x,int y,db z){ver[++tot]=y,nxt[tot]=head[x],_edge[tot]=z,head[x]=tot;}
    int n,m,s,t;
    int dis[maxn];
    int cur[maxn];
    bool bfs(){
    	memset(dis,-1,sizeof(dis));
    	queue<int>q;q.push(s);dis[s]=0;
    	while(!q.empty()){
    		int u=q.front();q.pop();
    		for(int i=head[u];i;i=nxt[i]){
    			int v=ver[i];
    			if(dis[v]==-1 && edge[i]>0){
    				dis[v]=dis[u]+1,q.push(v);
    			}
    		}
    	}
    	return (dis[t]!=-1);
    }
    db dfs(int u,db flow){
    	if(u==t)return flow;
    	db _flow=0,__flow;
    	for(int& i=cur[u];i;i=nxt[i]){
    		int v=ver[i];
    		if(dis[v]==dis[u]+1 && edge[i]>0){
    			__flow=dfs(v,min(flow,edge[i]));
    			flow-=__flow;
    			edge[i]-=__flow;
    			_flow+=__flow;
    			edge[i^1]+=__flow;
    			if(!flow)break;
    		}
    	}
    	if(!_flow)dis[u]=-1;
    	return _flow;
    }
    db dinic(){
    	db max_flow=0;
    	while(bfs()){
    		for(int i=1;i<=n*2+m+2;i++)cur[i]=head[i];
    		max_flow+=dfs(s,inf);
    	}
    	return max_flow;
    }
    int a[maxn],b[maxn],w[maxn];
    int rg(int x){return x;}
    int cg(int x){return x+n;}
    int gm(int x){return x+n*2;}
    int Sum=0;
    bool check(db x){
    	memcpy(edge,_edge,sizeof(_edge));
    	for(int i=head[s];i;i=nxt[i]){edge[i]=_edge[i]*x;}
    	for(int xx=gm(1);xx<=gm(m);xx++)for(int i=head[xx];i;i=nxt[i]){edge[i]=_edge[i]*x;}
    	if(abs(dinic()-Sum)<=eps)return 1;
    	else return 0;
    }
    signed main(){
    	n=read(),m=read();
    	s=n*2+m+1,t=n*2+m+2;
    	for(int i=1;i<=n;i++)Sum+=(a[i]=read()*1000),add(rg(i),cg(i),a[i]),add(cg(i),rg(i),0),add(cg(i),t,a[i]),add(t,cg(i),0);
    	for(int i=1;i<=m;i++)w[i]=read()*1000,add(s,gm(i),w[i]),add(gm(i),s,0);
    	db l=0,r=0;
    	for(int i=1;i<=m;i++){
    		db sum=0;
    		for(int j=1,op;j<=n;j++){
    			if((op=read()))add(gm(i),rg(j),w[i]),add(rg(j),gm(i),0);
    			if(op)sum+=a[j];
    		}
    		r=max(r,sum/w[i]+1);
    	}
    	while(r-l>eps){
    		db mid=(l+r)/2;
    		if(check(mid))r=mid;
    		else l=mid;
    	}
    	printf("%.6Lf
    ",r);
    }
    

    士兵占领

    思路

    这道题看起来是一个有下界的限制,转化一下,其实我们可以先把所有的可以放置士兵的位置都放上,然后考虑在符合条件的情况下,能去掉士兵的最大个数,就可以了

    code

    #include<bits/stdc++.h>
    #define ll long long
    #define il inline
    #define re register 
    #define gc getchar()
    #define getch while(ch<'0'||ch>'9'){if(ch=='-')f=-f;ch=gc;}
    #define getnu while(ch>='0'&&ch<='9'){s=(s<<1)+(s<<3)+ch-'0';ch=gc;}
    using namespace std;
    inline int read(){int s=0,f=1;char ch=gc;getch;getnu;return s*f;}
    const int maxn=300,maxm=2e5;
    const int inf=0x7f7f7f7f;
    int head[maxn],nxt[maxm<<1],ver[maxm<<1],edge[maxm<<1],tot=1;
    void add(int x,int y,int z){ver[++tot]=y,nxt[tot]=head[x],edge[tot]=z,head[x]=tot;}
    int k,n,m,s,t,cnt;
    int dis[maxn];
    int cur[maxn];
    il bool bfs(){
    	memset(dis,-1,sizeof(dis));
    	queue<int>q;q.push(s);dis[s]=0;
    	while(!q.empty()){
    		int u=q.front();q.pop();
    		for(int i=head[u];i;i=nxt[i]){
    			int v=ver[i];
    			if(dis[v]==-1 && edge[i]>0){
    				dis[v]=dis[u]+1,q.push(v);
    			}
    		}
    	}
    	return (dis[t]!=-1);
    }
    il int dfs(re int u,re int flow){
    	if(u==t)return flow;
    	int _flow=0,__flow;
    	for(int& i=cur[u];i;i=nxt[i]){
    		int v=ver[i];
    		if(dis[v]==dis[u]+1 && edge[i]>0){
    			__flow=dfs(v,min(flow,edge[i]));
    			flow-=__flow;
    			edge[i]-=__flow;
    			_flow+=__flow;
    			edge[i^1]+=__flow;
    			if(!flow)break;
    		}
    	}
    	if(!_flow)dis[u]=-1;
    	return _flow;
    }
    il void dinic(){
    	int max_flow=0;
    	while(bfs()){
    		for(int i=1;i<=n+m+2;i++)cur[i]=head[i];
    		max_flow+=dfs(s,inf);
    	}
    	printf("%d
    ",cnt-max_flow);
    }
    int l[maxn],c[maxn];
    bool vis[maxn][maxn];
    signed main(){
    	n=read(),m=read(),k=read();
    	s=n+m+1,t=n+m+2;
    	for(re int i=1;i<=n;i++)l[i]=read();
    	for(re int j=1;j<=m;j++)c[j]=read();
    	for(re int i=1;i<=k;i++){int x=read(),y=read();vis[x][y]=1;}
    	for(re int i=1;i<=n;i++){
    		for(re int j=1;j<=m;j++){
    			if(!vis[i][j])add(i,j+n,1),add(j+n,i,0),cnt++;
    			else l[i]++,c[j]++;
    		}
    	}
    	for(re int i=1;i<=n;i++)add(s,i,m-l[i]),add(i,s,0);
    	for(re int i=1;i<=m;i++)add(i+n,t,n-c[i]),add(t,i+n,0);
    	dinic();
    }
    

    紧急疏散evacuate

    思路

    一眼就感觉很能二分,二分能逃脱的时间,把每扇门都拆成当前二分时间个点,把每位置向它所能到达的门的最短时间连边,注意,同一扇门之间要从当前时间向下一时间连边,然后建超级原点,超级汇点就可以了,(可能空间开销比较大

    #include<bits/stdc++.h>
    #define ll long long
    #define il inline
    #define re register 
    #define gc getchar()
    #define getch while(ch<'0'||ch>'9'){if(ch=='-')f=-f;ch=gc;}
    #define getnu while(ch>='0'&&ch<='9'){s=(s<<1)+(s<<3)+ch-'0';ch=gc;}
    using namespace std;
    inline int read(){int s=0,f=1;char ch=gc;getch;getnu;return s*f;}
    const int maxn=25,maxm=2e5;
    const int inf=0x7f7f7f7f;
    int head[maxn*maxn*maxn*maxn],nxt[maxm<<1],ver[maxm<<1],edge[maxm<<1],tot=1;
    int g[maxn][maxn];
    int pos1[maxn*maxn],pos2[maxn*maxn];
    int DIS[maxn*maxn][maxn*maxn][maxn*maxn];
    char ch[maxn];
    void add(int x,int y,int z){
    	ver[++tot]=y,nxt[tot]=head[x],edge[tot]=z,head[x]=tot;
    }
    int d,R,k,n,m,s,t,cnt;
    int dis[maxn*maxn*maxn*maxn];
    int cur[maxn*maxn*maxn*maxn];
    il bool bfs(){
    	memset(dis,-1,sizeof(dis));
    	queue<int>q;q.push(s);dis[s]=0;
    	while(!q.empty()){
    		int u=q.front();q.pop();
    		for(int i=head[u];i;i=nxt[i]){
    			int v=ver[i];
    			if(dis[v]==-1 && edge[i]>0){
    				dis[v]=dis[u]+1,q.push(v);
    			}
    		}
    	}
    	return (dis[t]!=-1);
    }
    il int dfs(re int u,re int flow){
    	if(u==t)return flow;
    	int _flow=0,__flow;
    	for(int& i=cur[u];i;i=nxt[i]){
    		int v=ver[i];
    		if(dis[v]==dis[u]+1 && edge[i]>0){
    			__flow=dfs(v,min(flow,edge[i]));
    			flow-=__flow;
    			edge[i]-=__flow;
    			_flow+=__flow;
    			edge[i^1]+=__flow;
    			if(!flow)break;
    		}
    	}
    	if(!_flow)dis[u]=-1;
    	return _flow;
    }
    il int dinic(){
    	int max_flow=0;
    	while(bfs()){
    		for(int i=1;i<=t;i++)cur[i]=head[i];
    		max_flow+=dfs(s,inf);
    	}
    	return max_flow;
    }
    il bool check(int sec){
    	memset(head,0,sizeof(head));tot=1;
    	s=R+d*sec+1,t=R+d*sec+2;
    	for(int i=1;i<=n;i++)for(int j=1;j<=m;j++)
    		if(g[i][j]&&g[i][j]!=-1)add(s,g[i][j],1),add(g[i][j],s,0);
    	for(int k=1;k<=d;k++)for(int i=1;i<=n;i++)for(int j=1;j<=m;j++){
    		int Dis=DIS[k][i][j];
    		if(g[i][j]&&g[i][j]!=-1&&Dis<=sec)add(g[i][j],(k-1)*sec+R+Dis,1),add((k-1)*sec+R+Dis,g[i][j],0);
    	}
    	for(int i=1;i<=d;i++)for(int j=1;j<=sec;j++){
    		int S=(i-1)*sec+R+j;add(S,t,1);add(t,S,0);
    		if(j!=sec)add(S,S+1,inf),add(S+1,S,0);
    	}
    	return dinic()==R;
    }
    bool flag[maxn*maxn][maxn*maxn];
    queue<pair<int,int> >que;
    int dx[4]={0,1,0,-1};
    int dy[4]={1,0,-1,0};
    void pre(int sp){
    	memset(flag,0,sizeof(flag))	;
    	memset(DIS[sp],0x3f,sizeof(DIS[sp]));
    	DIS[sp][pos1[sp]][pos2[sp]]=0;
    	que.push(make_pair(pos1[sp],pos2[sp]));
    	while(!que.empty()){
    		pair<int,int> u=que.front();que.pop();flag[u.first][u.second]=0;
    		for(int i=0;i<4;i++){
    			pair<int,int> v;v.first=u.first+dx[i];v.second=u.second+dy[i];
    			if(!g[v.first][v.second]||g[v.first][v.second]==-1)continue;
    			if(DIS[sp][v.first][v.second]>DIS[sp][u.first][u.second]+1){
    				DIS[sp][v.first][v.second]=DIS[sp][u.first][u.second]+1;
    				if(!flag[v.first][v.second])que.push(make_pair(v.first,v.second)),flag[v.first][v.second];
    			}
    		}
    	}
    }
    signed main(){
    	n=read(),m=read();
    	for(int i=1;i<=n;i++){
    		scanf("%s",ch+1);
    		for(int j=1;j<=m;j++){
    			if(ch[j]=='.')g[i][j]=++R;
    			else if(ch[j]=='D')pos1[++d]=i,pos2[d]=j,g[i][j]=-1;
    		}
    	}
    	for(int i=1;i<=d;i++)pre(i);
    	int l=0,r=1000;
    	while(r-l>0){
    		if(r==l+1){
    			if(check(l))r=l;
    			break;
    		}
    		int mid=(l+r)>>1;
    		if(check(mid))r=mid;
    		else l=mid;
    	}
    	if(check(r))printf("%d
    ",r);
    	else puts("impossible");
    }
    

    狼抓兔子

    思路

    最小割的板子,然而正解是最短路??

    code

    
    
    #include<bits/stdc++.h>
    #define ll long long
    #define il inline
    #define re register 
    #define gc getchar()
    #define getch while(ch<'0'||ch>'9'){if(ch=='-')f=-f;ch=gc;}
    #define getnu while(ch>='0'&&ch<='9'){s=(s<<1)+(s<<3)+ch-'0';ch=gc;}
    using namespace std;
    inline int read(){int s=0,f=1;char ch=gc;getch;getnu;return s*f;}
    const int maxn=1000+10;
    int a[maxn][maxn],b[maxn][maxn],c[maxn][maxn];
    int head[maxn*maxn*2],nxt[maxn*6000],ver[maxn*6000],edge[maxn*6000],tot;
    int n,m,s,t;
    il void add(int x,int y,int z){ver[++tot]=y,nxt[tot]=head[x],edge[tot]=z,head[x]=tot;}
    int dis[maxn*maxn*2];
    bool vis[maxn*maxn*2];
    priority_queue<pair<int,int> >q;
    int getpos1(int x,int y){return (x-1)*(m-1)*2+(y-1)*2+1;}
    int getpos2(int x,int y){return (x-1)*(m-1)*2+(y-1)*2+2;}
    void dij(){
    	for(re int i=0;i<=t;i++)dis[i]=0x3f3f3f3f;
    	dis[s]=0;
    	q.push(make_pair(0,s));
    	while(!q.empty()){
    		int x=q.top().second;q.pop();
    		if(x==t)break;
    		if(vis[x])continue;
    		vis[x]=1;
    		for(re int i=head[x];i;i=nxt[i]){
    			int y=ver[i];
    			if(dis[y]>dis[x]+edge[i]){
    				dis[y]=dis[x]+edge[i];
    				q.push(make_pair(-dis[y],y));
    			}
    		}
    	}
    	printf("%d
    ",dis[t]);
    }
    int main(){
    	n=read(),m=read();
    	int Min=0x7f7f7f7f,Mmin=0x7f7f7f7f;
    	for(re int i=1;i<=n;i++)for(re int j=1;j<m;j++)Min=min(Min,(a[i][j]=read()));
    	for(re int i=1;i<n;i++)for(re int j=1;j<=m;j++)Mmin=min(Mmin,(b[i][j]=read()));
    	for(re int i=1;i<n;i++)for(re int j=1;j<m;j++)c[i][j]=read();
    	for(re int i=1;i<n;i++){
    		for(re int j=1;j<m;j++){
    			int pd1=getpos1(i,j);
    			if(i!=n-1){
    				int pd2=getpos2(i+1,j);
    				add(pd1,pd2,a[i+1][j]);add(pd2,pd1,a[i+1][j]);
    			}
    			int pd2=getpos2(i,j);
    			add(pd1,pd2,c[i][j]);add(pd2,pd1,c[i][j]);
    			if(j!=1){
    				int pd2=getpos2(i,j-1);
    				add(pd1,pd2,b[i][j]);add(pd2,pd1,b[i][j]);
    			}
    		}
    	}
    	if(m==1){printf("%d
    ",Mmin);return 0;}
    	if(n==1){printf("%d
    ",Min);return 0;}
    	s=(n-1)*(m-1)*2+1,t=s+1;
    	for(re int i=1;i<n;i++){
    		int pd=getpos1(i,1);
    		add(s,pd,b[i][1]);add(pd,s,b[i][1]);
    	}
    	for(re int j=1;j<m;j++){
    		int pd=getpos1(n-1,j);
    		add(s,pd,a[n][j]);add(pd,s,a[n][j]);
    	}
    	for(re int i=1;i<n;i++){
    		int pd=getpos2(i,m-1);
    		add(t,pd,b[i][m]);add(pd,t,b[i][m]);
    	}
    	for(re int j=1;j<m;j++){
    		int pd=getpos2(1,j);
    		add(t,pd,a[1][j]);add(pd,t,a[1][j]);
    	}
    	dij();
    }
    

    网络扩容

    思路

    第一问跑一遍最大流就可以了,对于第二问,在第一问的最大流的基础上建边,从超级原点向1号节点建一条上限为k的边,然后在原边的基础上再建一条权值为inf的边,跑最大流最小费用就可以了

    code

    #include<bits/stdc++.h>
    #define ll long long
    #define re register 
    #define gc getchar()
    #define getch while(ch<'0'||ch>'9'){if(ch=='-')f=-f;ch=gc;}
    #define getnu while(ch>='0'&&ch<='9'){s=(s<<1)+(s<<3)+ch-'0';ch=gc;}
    using namespace std;
    inline int read(){int s=0,f=1;char ch=gc;getch;getnu;return s*f;}
    const int maxn=5e3+10,maxm=5e4+10;
    int head[maxn],nxt[maxm<<1],ver[maxm<<1],e1[maxm<<1],e2[maxm<<1],tot=1;
    void add(int x,int y,int z1,int z2){ver[++tot]=y,nxt[tot]=head[x],e1[tot]=z1,e2[tot]=z2,head[x]=tot;}
    int n,m,s,t,k;
    struct node{int x,e;}pre[maxm<<1];
    int maxflow,cost,Min;
    bool vis[maxn];
    int dis[maxn];
    bool spfa(){
    	memset(dis,0x7f,sizeof(dis));
    	memset(vis,0,sizeof(vis));
    	memset(pre,-1,sizeof(pre));
    	queue<int>q;
    	q.push(s);dis[s]=0;vis[s]=1;
    	while(!q.empty()){
    		int u=q.front();q.pop();vis[u]=0;
    		for(int i=head[u];i;i=nxt[i]){
    			int v=ver[i];
    			if(e1[i]>0&&dis[v]>dis[u]+e2[i]){
    				dis[v]=dis[u]+e2[i];
    				pre[v].x=u;pre[v].e=i;
    				if(!vis[v])q.push(v),vis[v]=1;	
    			}
    		}
    	}
    	return dis[t]!=0x7f7f7f7f;
    }
    void EK(bool op){
    	maxflow=0,cost=0;
    	while(spfa()){
    		Min=0x7f7f7f7f;
    		for(int i=t;i!=s;i=pre[i].x){
    			Min=min(Min,e1[pre[i].e]);
    		}
    		for(int i=t;i!=s;i=pre[i].x)e1[pre[i].e]-=Min,e1[pre[i].e^1]+=Min;
    		maxflow+=Min;
    		cost+=Min*dis[t];
    	}
    	if(op)printf("%d ",maxflow);
    	else printf("%d
    ",cost);
    }
    signed main(){
    	n=read(),m=read(),k=read(),s=1,t=n;
    	for(int i=1;i<=m;i++){int x=read(),y=read(),z1=read(),z2=read();add(x,y,z1,z2);add(y,x,0,-z2);}
    	EK(1);
    	for(int x=1;x<=n;x++){
    		for(int i=head[x];i;i=nxt[i]){
    			if(e2[i]>0) add(x,ver[i],0x7f7f7f7f,e2[i]),add(ver[i],x,0,-e2[i]);
    			e2[i]=0;
    		}
    	}
    	add(n+1,1,k,0);add(1,n+1,0,0);
    	s=n+1;
    	EK(0);
    	return 0;
    }
    

    教辅的组成

    思路

    注意拆点,其他的没什么了

    code

    #include<bits/stdc++.h>
    #define ll long long
    #define il inline
    #define re register 
    #define gc getchar()
    #define getch while(ch<'0'||ch>'9'){if(ch=='-')f=-f;ch=gc;}
    #define getnu while(ch>='0'&&ch<='9'){s=(s<<1)+(s<<3)+ch-'0';ch=gc;}
    using namespace std;
    inline int read(){int s=0,f=1;char ch=gc;getch;getnu;return s*f;}
    const int maxn=5e4,maxm=1e6;
    const int inf=0x7f7f7f7f;
    int head[maxn],nxt[maxm<<1],ver[maxm<<1],edge[maxm<<1],tot=1;
    void add(int x,int y,int z){ver[++tot]=y,nxt[tot]=head[x],edge[tot]=z,head[x]=tot;}
    int s,t;
    int dis[maxn];
    int cur[maxn];
    il bool bfs(){
    	memset(dis,-1,sizeof(dis));
    	queue<int>q;q.push(s);dis[s]=0;
    	while(!q.empty()){
    		int u=q.front();q.pop();
    		for(int i=head[u];i;i=nxt[i]){
    			int v=ver[i];
    			if(dis[v]==-1 && edge[i]>0){
    				dis[v]=dis[u]+1,q.push(v);
    			}
    		}
    	}
    	return (dis[t]!=-1);
    }
    il int dfs(re int u,re int flow){
    	if(u==t)return flow;
    	int _flow=0,__flow;
    	for(int& i=cur[u];i;i=nxt[i]){
    		int v=ver[i];
    		if(dis[v]==dis[u]+1 && edge[i]>0){
    			__flow=dfs(v,min(flow,edge[i]));
    			flow-=__flow;
    			edge[i]-=__flow;
    			_flow+=__flow;
    			edge[i^1]+=__flow;
    			if(!flow)break;
    		}
    	}
    	if(!_flow)dis[u]=-1;
    	return _flow;
    }
    il void dinic(){
    	int max_flow=0;
    	while(bfs()){
    		for(int i=1;i<=t;i++)cur[i]=head[i];
    		max_flow+=dfs(s,inf);
    	}
    	printf("%d
    ",max_flow);
    }
    signed main(){
    	int n1=read(),n2=read(),n3=read();
    	int m1=read();
    	for(int i=1,x,y;i<=m1;i++)x=read(),y=read(),add(x,y+n1*2,0),add(y+n1*2,x,1);
    	int m2=read();
    	for(int i=1,x,y;i<=m2;i++)x=read(),y=read(),add(x+n1,y+n1*2+n2,1),add(y+n1*2+n2,x+n1,0);
    	for(int i=1;i<=n1;i++)add(i,i+n1,1),add(i+n1,i,0);
    	s=n1*2+n2+n3+1,t=s+1;
    	for(int i=1;i<=n2;i++)add(s,i+n1*2,1),add(i+n1*2,s,0);
    	for(int i=1;i<=n3;i++)add(i+n1*2+n2,t,1),add(t,i+n1*2+n2,0);
    	dinic();
    }
    
  • 相关阅读:
    获取窗口相对位置小工具
    关于抽奖概率的问题
    乔布斯的成功秘方:坚持思考两个问题
    清理svn生成的相关文件的小工具
    photoshop cs6 简体中文正式版下载
    .NET下office操作利器NPOI
    sql 取各组中的最大值
    c# winform 获取当前程序运行根目录
    C# Winform DataGridView使用总结 转
    c#安装数据库并自动修改Web.config类
  • 原文地址:https://www.cnblogs.com/soda-ma/p/13966438.html
Copyright © 2020-2023  润新知