2021.08.17 网络流
dinic算法
注意:
1.dinic一直循环出不去的原因
1.cnt=0 -> cnt=1
2.cur数组没有把head的数据复制过来
3.是memcpy而不是memcmp
2.每条边容量的大小
找到在整张图中唯一的量。
[P1345 USACO5.4]奶牛的电信Telecowmunication - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)
重点:
1.bfs返回值的不同写法
2.bfs记录的flow的值的不同写法
3.把一堆点分成两半变为把一堆边分成两半——拆点
使用链式向前星
注:仅第一份代码来自我自己。
//把删点转化为割边,只需要把一个点拆成两个点,并且这一对点之间cap=1
//连接的时候连接两头就行 
#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstring>
#include<queue>
using namespace std;
const int N=210;
int n,m,start,end,cnt=1,head[N],cur[N],dep[N],vis[N];
struct node{
	int to,next,val;
	//node(int u,int v,int f):to(u),next(v),val(f){}
}a[N*14];
inline int read(){
	int s=0,w=1;
	char ch=getchar();
	while(ch<'0'||ch>'9'){
		if(ch=='-')w=-1;
		ch=getchar();
	}
	while(ch<='9'&&ch>='0'){
		s=s*10+ch-'0';
		ch=getchar();
	}
	return s*w;
}
void add(int u,int v,int w){
	++cnt;
	a[cnt].to=v;
	a[cnt].next=head[u];
	a[cnt].val=w;
	head[u]=cnt;
}
int bfs(int s,int t){
	memset(dep,0,sizeof(dep));
	memcpy(cur,head,sizeof(head));
	queue<int>q;
	q.push(s);
	dep[s]=1;
	while(!q.empty()){
		int x=q.front();q.pop();
		for(int i=head[x];i;i=a[i].next){
			int v=a[i].to;
			if(a[i].val&&!dep[v])q.push(v),dep[v]=dep[x]+1;
		}
	}
	return dep[t];
}
int dfs(int x,int t,int f){
	//cout<<"    Case 3"<<endl;
	//f:可容纳的流量 ans:目前已经使用的流量(已经被增广过的)
	//流量可真贵啊!!! 
	if(x==t)return f;
	int ans=0;
	for(int i=cur[x];i&&ans<f;i=a[i].next){
		int v=a[i].to;
		cur[x]=i;
		if(a[i].val&&dep[v]==dep[x]+1){
			int fi=dfs(v,t,min(a[i].val,f-ans));
			//cout<<"    fi "<<fi<<endl;//
			if(fi>0)a[i].val-=fi,a[i^1].val+=fi,ans+=fi;
		}
	}
	//if(ans<f)dep[x]=-1;
	//cout<<"    Case 4 "<<ans<<endl;
	return ans;
}
int dinic(int s,int t){
	int flow=0,x;
	while(bfs(s,t)>0){
		//cout<<"   Case 1"<<endl;
		//memset(cur,0,sizeof(cur));
		if((x=dfs(s,t,1<<30)))flow+=x;//,cout<<"    Case 2"<<endl;
        //这里是一次性把同一遍bfs能找着的全部给搞出来,也有重复好几遍直到找不着的写法,如下:
	}
	return flow;
}
 /*
 int dfs ( int x, int val ) {
    int i, u, rec ;
    if ( x == t ) return val ;
    for ( i = be[x] ; i ; i = nxt[i] ) {
        u = to[i] ;
        if ( dis[u]==dis[x]+1 && w[i]>0 && (rec = dfs(u,min(val,w[i]))) ) {
            w[i] -= rec ;
            w[i^1] += rec ;
            return rec ;//不同点1:这里是找到一个就返回一个的值
        }
    }
}
int max_flow() {
    int rec = 0, u ;
    while ( bfs() ) { 
        while (u = dfs(s,zhf))
            rec += u ;//不同点2:因为不是一次性找完,所以要加个循环
    }
    return rec ;
}
*/
int main(){
	n=read();m=read();start=read();end=read();
	for(int i=1;i<=n;i++){
		add(i,i+n,1);add(i+n,i,0);
	}
	for(int i=1;i<=m;i++){
		int u,v;
		u=read();v=read();
		add(u+n,v,1<<30);add(v,u+n,0);
		add(v+n,u,1<<30);add(u,v+n,0);
	}
	cout<<dinic(start+n,end);
	return 0;
}
#include <bits/stdc++.h>
using namespace std ;
bool Read ( int &x, char c = getchar(), bool fg = 0 ) {
    for ( x = 0 ; !isdigit(c) ; c = getchar() ) if ( c == EOF ) return false ; else if ( c == '-' ) fg = 1 ;
    for ( ; isdigit(c) ; c = getchar() ) x = 10*x + c - '0' ;
    if (fg) x = -x ; return true ; //手写个读入不要嫌弃
}
const int maxn = 210, maxm = 3510, zhf = 1<<29 ;
int n, m, be[maxn], to[maxm], nxt[maxm], w[maxm], e = 1, dis[maxn], s, t ;
void add ( int x, int y, int z ) {
    to[++e] = y ;
    nxt[e] = be[x] ;
    be[x] = e ;
    w[e] = z ;
}
queue <int> Q ;
bool bfs() {
    memset ( dis, -1, sizeof(dis) ) ;
    int i, u, x ;
    while ( !Q.empty() ) Q.pop() ;
    Q.push(s) ;
    dis[s] = 0 ;
    while ( !Q.empty() ) {
        x = Q.front() ;
        Q.pop() ;
        if ( x == t ) return true ;
        for ( i = be[x] ; i ; i = nxt[i] ) {
            u = to[i] ;
            if ( dis[u] == -1 && w[i]>0 ) {
                dis[u] = dis[x]+1 ;
                if ( u == t ) return true ;
                Q.push(u) ;
            }
        }
    }
    return false ;    
}
int dfs ( int x, int val ) {
    int i, u, rec ;
    if ( x == t ) return val ;
    for ( i = be[x] ; i ; i = nxt[i] ) {
        u = to[i] ;
        if ( dis[u]==dis[x]+1 && w[i]>0 && (rec = dfs(u,min(val,w[i]))) ) {
            w[i] -= rec ;
            w[i^1] += rec ;
            return rec ;
        }
    }
}
int max_flow() {
    int rec = 0, u ;
    while ( bfs() ) { 
/*        for ( int i = 1 ; i <= 2*n ; i ++ )
            printf ( "dis[%d] = %d\n", i, dis[i] ) ;*/
        while (u = dfs(s,zhf))
            rec += u ;
    }
    return rec ;
}
int main() {
#ifndef ONLINE_JUDGE
    freopen ( "P1345.in", "r", stdin ) ;
    freopen ( "P1345.out", "w", stdout ) ;
#endif
    int i, j, k, x, y, z ;
    Read(n) ; Read(m) ;
    Read(s) ; Read(t) ;
    s += n ;
    for ( i = 1 ; i <= n ; i ++ ) {
        add ( i, i+n, 1 ) ;
        add ( i+n, i, 0 ) ;
    }
    
    for ( i = 1 ; i <= m ; i ++ ) {
        Read(x) ; Read(y) ;
        add ( y+n, x, zhf ) ;
        add ( x, y+n, 0 ) ;
        add ( x+n, y, zhf ) ;
        add ( y, x+n, 0 ) ;
    }
    
    printf ( "%d\n", max_flow() ) ;
    return 0 ;
}
使用vector
//Luogu P1345 [USACO5.4]奶牛的电信Telecowmunication
//June,3rd,2018
//割边转割点
#include<iostream>
#include<cstdio>
#include<cstring>
#include<vector>
#include<queue>
using namespace std;
long long read()
{
    long long x=0,f=1; char c=getchar();
    while(!isdigit(c)){if(c=='-') f=-1; c=getchar();}
    while(isdigit(c)){x=x*10+c-'0';c=getchar();}
    return x*f;
}
const int N=200+10;
const int inf=0x3f3f3f3f;
struct road
{
    int to,w,rev;
    road (int A,int B,int C)
    {
        to=A,w=B,rev=C;
    }
};
vector <road> e[N];
int n,m,c1,c2,depth[N];
queue <int> dl;
bool bfs()
{
    memset(depth,0,sizeof depth);
    depth[c1]=1;
    dl.push(c1);
    while(dl.empty()==false)
    {
        int now=dl.front();
        dl.pop();
        for(int i=0;i<int(e[now].size());i++)
            if(e[now][i].w>0 and depth[e[now][i].to]==0)
            {
                depth[e[now][i].to]=depth[now]+1;
                dl.push(e[now][i].to);
            }
    }
    if(depth[c2]==0) return false;
    return true;
}
int dfs(int now,int f)
{
    if(now==c2) return f;
    int ans=0;
    for(int i=0;i<int(e[now].size());i++)
        if(e[now][i].w>0 and depth[e[now][i].to]==depth[now]+1)
        {
            int temp=dfs(e[now][i].to,min(f,e[now][i].w));
            e[now][i].w-=temp;
            e[e[now][i].to][e[now][i].rev].w+=temp;
            f-=temp,ans+=temp;//不同点3:这里的f也在一直改变,所以说f本身就代表了还剩下可以走的流量,同时ans也在跟着变化(废话),所以比较的时候只需要比较a[i].val与f,选出最小值即可
            if(f==0) break;
        }
    return ans;
}
int Dinic()
{
    int ans=0;
    while(bfs()==true)
        ans+=dfs(c1,inf);
    return ans;
}
inline void AddLine(int s,int t,int w)
{
    e[s].push_back(road(t,w,e[t].size()));
    e[t].push_back(road(s,0,e[s].size()-1));
}
int main()
{
    n=read(),m=read(),c1=read(),c2=read();
    for(int i=1;i<=n;i++) e[i].reserve(8);
    for(int i=1;i<=n;i++)
        if(i==c1 or i==c2)
            AddLine(i,i+n,inf);
        else
            AddLine(i,i+n,1);
    for(int i=1;i<=m;i++)
    {
        int s=read(),t=read();
        AddLine(s+n,t,inf);
        AddLine(t+n,s,inf);
    }
    
    printf("%d",Dinic());
    return 0;
}
P1361 小M的作物 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)
重点:
1.建图的神奇的逻辑关系
2.把一堆边分两半可以用最小割
分析及代码:
//对于一个点集X,X可以对A有贡献,对B有贡献,或者对A、B都没有贡献
//所以可以把A、B当成超级源点和超级汇点
//对于每一个组合,可以把每一个组合当成一种巨大作物处理,但是不能是和原来单种作物处于同一个等级
//必须对巨大作物再加一个小超级源点和小超级汇点,这两个点处于普通作物与超级源点和超级汇点之间的等级 
//麻溜地求最小割,斩断情丝~ 
#include<cstdio>
#include<iostream>
#include<algorithm>
#include<queue>
#include<cstring>
using namespace std;
const int N=3010;
int n,m,start,end,cnt=1,tot,head[N],ai[N],bi[N],dep[N],cur[N];
struct node{
	int to,next,val;
}a[N*2*1000];
inline int read(){
	int s=0,w=1;
	char ch=getchar();
	while(ch<'0'||ch>'9'){
		if(ch=='-')w=-1;
		ch=getchar();
	}
	while(ch<='9'&&ch>='0'){
		s=s*10+ch-'0';
		ch=getchar(); 
	}
	return s*w;
}
void add(int u,int v,int w){
	++cnt;
	a[cnt].to=v;
	a[cnt].val=w;
	a[cnt].next=head[u];
	head[u]=cnt;
}
void addi(int u,int v,int w){
	add(u,v,w);add(v,u,0);
}
int id(int level,int x){
	if(level==1)return x;//小超级源点级 
	else if(level==2)return m+x;//普通作物级 
	else if(level==3)return m+n+x;//小超级汇点级 
}
int bfs(int s,int t){
	memset(dep,0,sizeof(dep));
	memcpy(cur,head,sizeof(head));
	queue<int>q;
	q.push(s);dep[s]=1;
	while(!q.empty()){
		int x=q.front();q.pop();
		for(int i=head[x];i;i=a[i].next){
			int v=a[i].to;
			if(a[i].val&&!dep[v])q.push(v),dep[v]=dep[x]+1;
		}
	}
	return dep[t];
}
int dfs(int x,int t,int f){
	if(x==t)return f;
	int ans=0;
	for(int i=cur[x];i&&ans<f;i=a[i].next){
		cur[x]=i;
		int v=a[i].to;
		int fi=0;
		if(a[i].val&&dep[v]==dep[x]+1&&(fi=dfs(v,t,min(a[i].val,f-ans)))>0)
		//注意括号的对应关系!!! 
		a[i].val-=fi,a[i^1].val+=fi,ans+=fi;
	}
	return ans;
}
int dinic(int s,int t){
	int flow=0;
	while(bfs(s,t)){
		int x=0;
		if((x=dfs(s,t,1<<30))>0)flow+=x;
	}
	return flow;
}
int main(){
	n=read();
	for(int i=1;i<=n;i++)ai[i]=read(),tot+=ai[i];
	for(int i=1;i<=n;i++)bi[i]=read(),tot+=bi[i];
	m=read();
	start=0,end=m+n+m+1;
	for(int i=1;i<=n;i++)
		addi(start,id(2,i),ai[i]),addi(id(2,i),end,bi[i]);
	//m=read();
	for(int i=1;i<=m;i++){
		int k,c1,c2,i1=id(1,i),i3=id(3,i);
		k=read();c1=read();c2=read();
		for(int j=1;j<=k;j++){
			int u=read();
			addi(i1,id(2,u),1<<30);
			addi(id(2,u),i3,1<<30);
		}
		addi(start,i1,c1);addi(i3,end,c2);
		tot+=(c1+c2);//shift!没看见是额外收益,我还减了减,无语望天 
	}
	cout<<tot-dinic(start,end);
	return 0;
}
[P2057 SHOI2007]善意的投票 / [JLOI2010]冠军调查 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)
//一波无脑最小割
//start连idea为1的,end连idea为0的,朋友之间相连
#include<cstdio>
#include<iostream>
#include<algorithm>
#include<queue>
#include<cstring> 
using namespace std;
const int N=310;
const int M=91240;
int n,m,start,end,idea[N],dep[M],cur[M],cnt=1,head[M];
struct node{
	int to,next,val;
}a[M*2];
inline int read(){
	int s=0,w=1;
	char ch=getchar();
	while(ch<'0'||ch>'9'){
		if(ch=='-')w=-1;
		ch=getchar();
	}
	while(ch<='9'&&ch>='0'){
		s=s*10+ch-'0';
		ch=getchar(); 
	}
	return s*w;
}
void add(int u,int v,int w){
	++cnt;
	a[cnt].to=v;
	a[cnt].val=w;
	a[cnt].next=head[u];
	head[u]=cnt;
}
void addi(int u,int v,int w){
	add(u,v,w);add(v,u,0);
}
int bfs(int s,int t){
	memset(dep,0,sizeof(dep));
	memcpy(cur,head,sizeof(head));
	queue<int>q;
	q.push(s);dep[s]=1;
	while(!q.empty()){
		int x=q.front();q.pop();
		for(int i=head[x];i;i=a[i].next){
			int v=a[i].to;
			if(!dep[v]&&a[i].val)q.push(v),dep[v]=dep[x]+1;
		}
	}
	return dep[t];
}
int dfs(int x,int t,int f){
	if(x==t)return f;
	int ans=0;
	for(int i=cur[x];i&&ans<f;i=a[i].next){
		cur[x]=i;
		int v=a[i].to;
		int fi=0;
		if(dep[v]==dep[x]+1&&a[i].val&&(fi=dfs(v,t,min(a[i].val,f-ans)))>0)
		a[i].val-=fi,a[i^1].val+=fi,ans+=fi;
	}
	return ans;
}
void dinic(int s,int t){
	int flow=0;
	while(bfs(s,t)){
		//cout<<"   case 1"<<endl;
		int x=0;
		if((x=dfs(s,t,1<<30))>0)flow+=x;
		//cout<<"    case 2 "<<x<<" "<<flow<<endl;
	}
	cout<<flow;
}
int main(){
	n=read();m=read();
	start=0,end=2*n+1;
	for(int i=1;i<=n;i++){
		idea[i]=read();
		if(idea[i])addi(start,i,1);//,cout<<"    CASE 1"<<endl;
		else addi(i,end,1);//,cout<<"    CASE 0"<<endl;
		//cout<<" "<<idea[i]<<" ";
	}
	for(int i=1;i<=m;i++){
		int u,v;
		u=read();v=read();
		addi(u,v,1);addi(v,u,1);
	}
	dinic(start,end);
	return 0;
}
P4313 文理分科 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)
重点:
1.空间不能开得刚刚好,因为出题人脑子会抽抽
代码如下:
//这与农作物那题极其相似
//所以,再来一波迅速的最小割
//分析就舍去了
#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstring>
#include<queue>
using namespace std;
const int N=110;
const int M=200000;
int n,m,cnt=1,tot,ai[N][N],bi[N][N],start,end,head[M],dep[M],cur[M];
struct node{
	int to,next,val;
}a[M];
inline int read(){
	int s=0,w=1;
	char ch=getchar();
	while(ch<'0'||ch>'9'){
		if(ch=='-')w=-1;
		ch=getchar();
	}
	while(ch<='9'&&ch>='0'){
		s=s*10+ch-'0';
		ch=getchar(); 
	}
	return s*w;
}
void addi(int u,int v,int w){
	++cnt;
	a[cnt].to=v;
	a[cnt].val=w;
	a[cnt].next=head[u];
	head[u]=cnt;
}
void add(int u,int v,int w){
	addi(u,v,w);addi(v,u,0);
}
int id(int level,int x){
	if(level==1)return x;
	else if(level==2)return n*m+x;
	else if(level==3)return n*m+n*m+x;
}
int bfs(int s,int t){
	memset(dep,0,sizeof(dep));
	memcpy(cur,head,sizeof(head));
	queue<int>q;
	q.push(s);dep[s]=1;
	while(!q.empty()){
		int x=q.front();q.pop();
		for(int i=head[x];i;i=a[i].next){
			int v=a[i].to;
			if(!dep[v]&&a[i].val)q.push(v),dep[v]=dep[x]+1;
		}
	}
	return dep[t];
}
int dfs(int x,int t,int f){
	if(x==t)return f;
	int ans=0;
	for(int i=cur[x];i&&ans<f;i=a[i].next){
		int v=a[i].to;
		cur[x]=i;
		int fi=0;
		if(a[i].val&&dep[v]==dep[x]+1&&(fi=dfs(v,t,min(a[i].val,f-ans)))>0)
		a[i].val-=fi,a[i^1].val+=fi,ans+=fi;
	}
	return ans;
}
int dinic(int s,int t){
	int flow=0;
	while(bfs(s,t)){
		int x=0;
		if((x=dfs(s,t,1<<30))>0)flow+=x;
	}
	return flow;
}
int main(){
	n=read();m=read();
	start=0;end=3*n*m+1;
	for(int i=1;i<=n;i++)for(int j=1;j<=m;j++){
		ai[i][j]=read();
		tot+=ai[i][j];
		add(start,id(2,(i-1)*m+j),ai[i][j]);
	}
	for(int i=1;i<=n;i++)for(int j=1;j<=m;j++){
		bi[i][j]=read();
		tot+=bi[i][j];
		add(id(2,(i-1)*m+j),end,bi[i][j]);
	}
	for(int i=1;i<=n;i++)for(int j=1;j<=m;j++){
		ai[i][j]=read();
		tot+=ai[i][j];
		int xi=id(2,(i-1)*m+j);
		int starti=id(1,(i-1)*m+j);
		add(start,starti,ai[i][j]);
		add(starti,xi,1<<30);
		if(j!=1)add(starti,xi-1,1<<30);
		if(j!=m)add(starti,xi+1,1<<30);
		if(i!=1)add(starti,xi-m,1<<30);
		if(i!=n)add(starti,xi+m,1<<30);
	}
	for(int i=1;i<=n;i++)for(int j=1;j<=m;j++){
		bi[i][j]=read();
		tot+=bi[i][j];
		int xi=id(2,(i-1)*m+j);
		int endi=id(3,(i-1)*m+j);
		add(endi,end,bi[i][j]);
		add(xi,endi,1<<30);
		if(j!=1)add(xi-1,endi,1<<30);
		if(j!=m)add(xi+1,endi,1<<30);
		if(i!=1)add(xi-m,endi,1<<30);
		if(i!=n)add(xi+m,endi,1<<30);
	}
	cout<<tot-dinic(start,end);
	return 0;
}
[P2598 ZJOI2009]狼和羊的故事 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)
//难道出题人没看过喜羊羊与灰太狼吗?
#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstring>
#include<queue>
using namespace std;
const int N=110;
const int M=10010;
int n,m,cnt=1,start,end,ai[N][N],head[M],cur[M],dep[M];
struct node{
	int to,next,val;
}a[M<<1];
inline int read(){
	int s=0,w=1;
	char ch=getchar();
	while(ch<'0'||ch>'9'){
		if(ch=='-')w=-1;
		ch=getchar();
	}
	while(ch<='9'&&ch>='0'){
		s=s*10+ch-'0';
		ch=getchar(); 
	}
	return s*w;
}
void addi(int u,int v,int w){
	++cnt;
	a[cnt].to=v;
	a[cnt].val=w;
	a[cnt].next=head[u];
	head[u]=cnt;
}
void add(int u,int v,int w){
	addi(u,v,w);addi(v,u,0);
}
int bfs(int s,int t){
	memset(dep,0,sizeof(dep));
	memcpy(cur,head,sizeof(head));
	queue<int>q;
	q.push(s);dep[s]=1;
	while(!q.empty()){
		int x=q.front();q.pop();
		for(int i=head[x];i;i=a[i].next){
			int v=a[i].to;
			if(!dep[v]&&a[i].val)q.push(v),dep[v]=dep[x]+1;
		}
	}
	return dep[t];
}
int dfs(int x,int t,int f){
	if(x==t)return f;
	int ans=0;
	for(int i=cur[x];i&&ans<f;i=a[i].next){
		int v=a[i].to;
		cur[x]=i;
		int fi=0;
		if(a[i].val&&dep[v]==dep[x]+1&&(fi=dfs(v,t,min(a[i].val,f-ans)))>0)
		a[i].val-=fi,a[i^1].val+=fi,ans+=fi;
	}
	return ans;
}
int dinic(int s,int t){
	int flow=0;
	while(bfs(s,t)){
		int x=0;
		if((x=dfs(s,t,1<<30))>0)flow+=x;
	}
	return flow;
}
int main(){
	n=read();m=read();
	start=0,end=n*m+1;
	for(int i=1;i<=n;i++)for(int j=1;j<=m;j++){
		ai[i][j]=read();
		if(ai[i][j]==1)add(start,(i-1)*m+j,1<<30);//毕竟一头狼可能有好几个羊邻居
		else if(ai[i][j]==2)add((i-1)*m+j,end,1<<30); 
	}
	for(int i=1;i<=n;i++)for(int j=1;j<=m;j++){
		int xi=(i-1)*m+j;
		if(j!=1)add(xi,xi-1,1);
		if(j!=m)add(xi,xi+1,1);
		if(i!=1)add(xi,xi-m,1);
		if(i!=n)add(xi,xi+m,1);
		/*
		if(j!=1&&ai[i][j]!=ai[i][j-1])add(xi,xi-1,1),add(xi-1,xi,1);
		if(j!=m&&ai[i][j]!=ai[i][j+1])add(xi,xi+1,1),add(xi+1,xi,1);
		if(i!=1&&ai[i][j]!=ai[i-1][j])add(xi,xi-m,1),add(xi-m,xi,1);
		if(i!=n&&ai[i][j]!=ai[i+1][j])add(xi,xi+m,1),add(xi+m,xi,1);
		*/
		/*
		if(j!=1&&ai[i][j]!=ai[i][j-1]){
			if(ai[i][j]==1)add(xi,xi-1,1);
			else if(ai[i][j]==2)add(xi-1,xi,1);
		}
		if(j!=m&&ai[i][j]!=ai[i][j+1]){
			if(ai[i][j]==1)add(xi,xi+1,1);
			else if(ai[i][j]==2)add(xi+1,xi,1);
		}
		if(i!=1&&ai[i][j]!=ai[i-1][j]){
			if(ai[i][j]==1)add(xi,xi-m,1);
			else if(ai[i][j]==2)add(xi-m,xi,1);
		}
		if(i!=n&&ai[i][j]!=ai[i+1][j]){
			if(ai[i][j]==1)add(xi,xi+m,1);
			else if(ai[i][j]==2)add(xi+m,xi,1);
		}
		*/
        //以上两大段无用的代码简直是“赚得行人错喜欢”!
	}
	cout<<dinic(start,end);
	return 0;
} 
P2774 方格取数问题 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)
注:完美,这次预计的边的数量刚刚好~
//给棋盘进行染色,相邻两个颜色不同
//白色棋格全连在超级源点上,黑色棋格全连在超级汇点上,容量均为自身点权 
//每个白色棋格连在与之有关联的黑色棋格上,容量为inf 
#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstring>
#include<queue>
using namespace std;
const int N=110;
const int M=10010;
int n,m,tot,cnt=1,start,end,head[M],cur[M],dep[M];
struct node{
	int to,next,val;
}a[M*6];
inline int read(){
	int s=0,w=1;
	char ch=getchar();
	while(ch<'0'||ch>'9'){
		if(ch=='-')w=-1;
		ch=getchar();
	}
	while(ch<='9'&&ch>='0'){
		s=s*10+ch-'0';
		ch=getchar(); 
	}
	return s*w;
}
void addi(int u,int v,int w){
	++cnt;
	a[cnt].to=v;
	a[cnt].val=w;
	a[cnt].next=head[u];
	head[u]=cnt;
}
void add(int u,int v,int w){
	addi(u,v,w);addi(v,u,0);
}
int bfs(int s,int t){
	memset(dep,0,sizeof(dep));
	memcpy(cur,head,sizeof(head));
	queue<int>q;
	q.push(s);dep[s]=1;
	while(!q.empty()){
		int x=q.front();q.pop();
		for(int i=head[x];i;i=a[i].next){
			int v=a[i].to;
			if(!dep[v]&&a[i].val)q.push(v),dep[v]=dep[x]+1;
		}
	}
	return dep[t];
}
int dfs(int x,int t,int f){
	if(x==t)return f;
	int ans=0;
	for(int i=cur[x];i&&ans<f;i=a[i].next){
		int v=a[i].to;
		cur[x]=i;
		int fi=0;
		if(a[i].val&&dep[v]==dep[x]+1&&(fi=dfs(v,t,min(a[i].val,f-ans)))>0)
		a[i].val-=fi,a[i^1].val+=fi,ans+=fi;
	}
	return ans;
}
int dinic(int s,int t){
	int flow=0;
	while(bfs(s,t)){
		int x=0;
		if((x=dfs(s,t,1<<30))>0)flow+=x;
	}
	return flow;
}
int main(){
	n=read();m=read();
	start=0,end=n*m+1;
	for(int i=1;i<=n;i++)for(int j=1;j<=m;j++){
		int x=read();
		tot+=x;
		if((i+j)%2==1)add(start,(i-1)*m+j,x);
		else add((i-1)*m+j,end,x);
	}
	for(int i=1;i<=n;i++)for(int j=1;j<=m;j++){
		if((i+j)%2==0)continue;
		int xi=(i-1)*m+j;
		if(j!=1)add(xi,xi-1,1<<30);
		if(j!=m)add(xi,xi+1,1<<30);
		if(i!=1)add(xi,xi-m,1<<30);
		if(i!=n)add(xi,xi+m,1<<30);
	}
	cout<<tot-dinic(start,end);
	return 0;
} 
EK
注意:
1.spfa返回不了原因
1.if(dis[v]>dis[x]+a[i].cost&&a[i].val>0)忘记判断a[i].
[P2053 SCOI2007]修车 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)
#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstring>
#include<queue>
using namespace std;
//#define int long long
const int N=6700;
const int inf=0x3f3f3f3f;
int n,m,start,end,cnt=1,head[N],dis[N],pre[N],flow[N],vis[N],ai[65][65];
int maxncost,maxnflow;
struct node{
	int to,next,val,cost;
}a[740000];
inline int read(){
	int s=0,w=1;
	char ch=getchar();
	while(ch<'0'||ch>'9'){
		if(ch=='-')w=-1;
		ch=getchar();
	}
	while(ch<='9'&&ch>='0'){
		s=s*10+ch-'0';
		ch=getchar();
	}
	return s*w;
}
void addi(int u,int v,int w,int x){
	++cnt;
	a[cnt].to=v;
	a[cnt].val=w;
	a[cnt].cost=x;
	a[cnt].next=head[u];
	head[u]=cnt;
}
void add(int u,int v,int w,int x){
	addi(u,v,w,x);addi(v,u,0,-x);
}
int spfa(int s,int t){
	memset(dis,inf,sizeof(dis));
	memset(vis,0,sizeof(vis));
	queue<int>q;
	q.push(s);
	vis[s]=1;dis[s]=0;flow[s]=inf;
	while(!q.empty()){
		int x=q.front();q.pop();
		vis[x]=0;
		for(int i=head[x];i;i=a[i].next){
			int v=a[i].to;
			if(dis[v]>dis[x]+a[i].cost&&a[i].val>0){
				dis[v]=dis[x]+a[i].cost;
				flow[v]=min(flow[x],a[i].val);
				pre[v]=i;
				if(!vis[v])q.push(v),vis[v]=1;
			}
		}
	}
	return dis[t]!=inf;
}
void update(int s,int t){
	int x=t;
	while(x!=s){
		int xi=pre[x];
		a[xi].val-=flow[t];
		a[xi^1].val+=flow[t];
		x=a[xi^1].to;
	}
	maxnflow+=flow[t];
	maxncost+=flow[t]*dis[t];
}
void ek(int s,int t){
	while(spfa(s,t))update(s,t);//,cout<<"   Case 1"<<endl;
}
int id(int level,int x){
	if(level==1)return x;
	else if(level==2)return n*m+x;
}
signed main(){
	m=read();n=read();
	start=0,end=m*n+n+1;
	for(int i=1;i<=n;i++)for(int j=1;j<=m;j++){
		ai[i][j]=read();
		add(start,id(1,(i-1)*m+j),1,0);
	}
	for(int i=1;i<=n;i++)add(id(2,i),end,1,0);
	for(int i=1;i<=m;i++)for(int j=1;j<=n;j++)
	for(int k=1;k<=n;k++){
		int x=(i-1)*n+k;
		add(x,id(2,j),1,ai[j][i]*k);
	}
	ek(start,end);
	printf("%.2lf",(double)maxncost/(double)n);
	return 0;
}
 
                    
                     
                    
                 
                    
                 posted on
 posted on 
 
                
            
         
         浙公网安备 33010602011771号
浙公网安备 33010602011771号