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
浙公网安备 33010602011771号