能力提升综合题单Part 8.9.3 费用流
- P3381 【模板】最小费用最大流
- P4016 负载平衡问题
- P4452 [国家集训队]航班安排
- P2045 方格取数加强版
- P2050 [NOI2012]美食节
- P2053 [SCOI2007]修车
- P2604 [ZJOI2010]网络扩容
- P2770 航空路线问题
- P3159 [CQOI2012]交换棋子
- P3356 火星探险问题
- P3358 最长k可重区间集问题
- P4013 数字梯形问题
- P4015 运输问题
- P5331 [SNOI2019]通信
1.P3381 【模板】最小费用最大流
类dinicdinicdinic的spfaspfaspfa费用流,多路增广效率较高(然而平时用的是EKEKEK)
#include<bits/stdc++.h>
using namespace std;
const int inf=0x3f3f3f3f,maxn=5e3+5,maxm=5e4+5;
int n,m,s,t,cost,maxflow,vis[maxn],dis[maxn];
struct edge{int v,flow,cost,rev;
};
vector<edge>e[maxm*2];
bool spfa(){memset(vis,0,sizeof(vis));memset(dis,inf,sizeof(dis));dis[s]=0;vis[s]=1;queue<int>q;q.push(s);while(!q.empty()){int u=q.front();q.pop();vis[u]=0;for(int i=0;i<e[u].size();i++){int v=e[u][i].v;int c=e[u][i].cost;if(dis[v]>dis[u]+c&&e[u][i].flow){dis[v]=dis[u]+c;if(vis[v]==0){q.push(v);vis[v]=1;}}}}if(dis[t]!=inf)return true;return false;
}
int dfs(int u,int flow){if(u==t){vis[t]=1;maxflow+=flow;return flow;}int used=0;vis[u]=1;for(int i=0;i<e[u].size();i++){int v=e[u][i].v;int c=e[u][i].cost;if((vis[v]==0||v==t)&&e[u][i].flow!=0&&dis[v]==dis[u]+c){int minflow=dfs(v,min(flow-used,e[u][i].flow));if(minflow!=0){cost+=c*minflow;e[u][i].flow-=minflow;e[v][e[u][i].rev].flow+=minflow;used+=minflow;if(used==flow)break;}}}return used;
}
int mcmf(){while(spfa()){vis[t]=1;while(vis[t]){memset(vis,0,sizeof(vis));dfs(s,inf);}}return maxflow;
}
int main(){scanf("%d%d%d%d",&n,&m,&s,&t);int u,v,f,w;for(int i=1;i<=m;i++){scanf("%d%d%d%d",&u,&v,&f,&w);e[u].push_back((edge){v,f,w,e[v].size()});e[v].push_back((edge){u,0,-w,e[u].size()-1});}mcmf();printf("%d %d",maxflow,cost);return 0;
}
2.P4016 负载平衡问题
每个点向旁边的点连边,流量为infinfinf, 费用111
每个点向汇点连一条边,流量为averageaverageaverage,费用000
#include<bits/stdc++.h>
#define int long long
using namespace std;
const int inf=0x3f3f3f3f,maxn=1005,maxm=100005;
struct edge{int nex,v,cost,flow;
}e[maxm];
int head[maxn],cnt=1;
int n,m;
inline void add_edge(int u,int v,int cost,int flow){e[++cnt].v=v;e[cnt].cost=cost;e[cnt].flow=flow;e[cnt].nex=head[u];head[u]=cnt;e[++cnt].v=u;e[cnt].cost=-cost;e[cnt].flow=0;e[cnt].nex=head[v];head[v]=cnt;
}
int inque[maxn];
int dis[maxn],flow[maxn],pre[maxn],last[maxn];
bool spfa(int s,int t){queue<int>q;memset(dis,0x3f,sizeof dis);memset(flow,0x3f,sizeof flow);memset(inque,0,sizeof inque);q.push(s);inque[s]=1;dis[s]=0;pre[t]=-1;while(!q.empty()){int u=q.front();q.pop();inque[u]=0;for(int i=head[u];i;i=e[i].nex){int v=e[i].v;if(dis[v]>dis[u]+e[i].cost&&e[i].flow){dis[v]=dis[u]+e[i].cost;pre[v]=u;last[v]=i;flow[v]=min(flow[u],e[i].flow);if(!inque[v]){q.push(v);inque[v]=1;}}}}if(pre[t]!=-1)return true;return false;
}
int maxflow,mincost;
void mcmf(int s,int t){maxflow=0;mincost=0;while(spfa(s,t)){int u=t;
// printf("maxflow==%d %d %d\n",maxflow,flow[t],flow[t]*dis[t]);maxflow+=flow[t];mincost+=flow[t]*dis[t];while(u!=s){e[last[u]].flow-=flow[t];e[last[u]^1].flow+=flow[t];u=pre[u];}}return;
}
signed main(){cin>>n;int s=n+1;int t=n+2;int x=0,sum=0;for(int i=1;i<=n;i++){cin>>x;sum+=x;add_edge(s,i,0,x);if(i!=n){add_edge(i,i+1,1,inf);}else{add_edge(n,1,1,inf);}if(i!=1){add_edge(i,i-1,1,inf);}else{add_edge(1,n,1,inf);}}int av=sum/n;for(int i=1;i<=n;i++){add_edge(i,t,0,av);}mcmf(s,t);cout<<mincost;return 0;
}
3.P4452 [国家集训队]航班安排
枚举每一趟航班,如果第 iii趟的结束时间+++ iii到jjj的飞行时间<j<j<j的出发时间,iii和jjj连边
(费用全为fff,流量为infinfinf,源点流出的流量为kkk)
#include<bits/stdc++.h>
using namespace std;
typedef pair<int,int> pii;
const int inf=0x3f3f3f3f,maxn=20005,maxm=400005;
struct edge{int nex,v,cost,flow;
}e[maxm];
int head[maxn],cnt=1;
int n,m,k,T;
inline void add_edge(int u,int v,int cost,int flow){e[++cnt].v=v;e[cnt].cost=cost;e[cnt].flow=flow;e[cnt].nex=head[u];head[u]=cnt;e[++cnt].v=u;e[cnt].cost=-cost;e[cnt].flow=0;e[cnt].nex=head[v];head[v]=cnt;
}
int inque[maxn],dis[maxn],flow[maxn],pre[maxn],last[maxn];
bool spfa(int s,int t){queue<int>q;memset(dis,0x3f,sizeof dis);memset(flow,0x3f,sizeof flow);memset(inque,0,sizeof inque);q.push(s);inque[s]=1;dis[s]=0;pre[t]=-1;while(!q.empty()){int u=q.front();q.pop();inque[u]=0;for(int i=head[u];i;i=e[i].nex){int v=e[i].v;if(dis[v]>dis[u]+e[i].cost&&e[i].flow){dis[v]=dis[u]+e[i].cost;pre[v]=u;last[v]=i;flow[v]=min(flow[u],e[i].flow);if(!inque[v]){q.push(v);inque[v]=1;}}}}if(pre[t]!=-1)return true;return false;
}
inline pair<int,int> mcmf(int s,int t){int maxflow=0;int mincost=0;while(spfa(s,t)){int u=t;maxflow+=flow[t];mincost+=flow[t]*dis[t];while(u!=s){e[last[u]].flow-=flow[t];e[last[u]^1].flow+=flow[t];u=pre[u];}}return {maxflow,mincost};
}
int t[205][205],f[205][205];
struct node{int a,b,s,t,c;
}q[505];
int main(){cin>>n>>m>>k>>T;for(int i=0;i<n;i++){for(int j=0;j<n;j++){scanf("%d",&t[i][j]);}}for(int i=0;i<n;i++){for(int j=0;j<n;j++){scanf("%d",&f[i][j]);}}for(int i=0;i<m;i++){scanf("%d%d%d%d%d",&q[i].a,&q[i].b,&q[i].s,&q[i].t,&q[i].c);}int tt=2*m+1;int st=2*m+2;int ed=2*m+3;for(int i=0;i<m;i++){add_edge(i,i+m,-q[i].c,1);if(t[q[i].b][0]+q[i].t<=T){add_edge(i+m,ed,f[q[i].b][0],inf);}else continue;if(q[i].s>=t[0][q[i].a]){add_edge(tt,i,f[0][q[i].a],inf);}for(int j=0;j<m;j++){if(t[q[i].b][q[j].a]+q[i].t<=q[j].s){add_edge(i+m,j,f[q[i].b][q[j].a],inf);}}}add_edge(st,tt,0,k);pii yaoyao=mcmf(st,ed);cout<<-yaoyao.second;return 0;
}
4.P2045 方格取数加强版
拆点,一条费用为 −-−点权,流量为111,另外一条费用000,流量infinfinf
#include<bits/stdc++.h>
#define int long long
using namespace std;
const int inf=0x3f3f3f3f,maxn=100005,maxm=400005;
struct edge{int nex,v,cost,flow;
}e[maxm];
int head[maxn],cnt=1;
int n,m,k;
inline void add_edge(int u,int v,int cost,int flow){e[++cnt].v=v;e[cnt].cost=cost;e[cnt].flow=flow;e[cnt].nex=head[u];head[u]=cnt;e[++cnt].v=u;e[cnt].cost=-cost;e[cnt].flow=0;e[cnt].nex=head[v];head[v]=cnt;
}
int inque[maxn];
int dis[maxn],flow[maxn],pre[maxn],last[maxn];
bool spfa(int s,int t){queue<int>q;memset(dis,0x3f,sizeof dis);memset(flow,0x3f,sizeof flow);memset(inque,0,sizeof inque);q.push(s);inque[s]=1;dis[s]=0;pre[t]=-1;while(!q.empty()){int u=q.front();q.pop();inque[u]=0;for(int i=head[u];i;i=e[i].nex){int v=e[i].v;if(dis[v]>dis[u]+e[i].cost&&e[i].flow){dis[v]=dis[u]+e[i].cost;pre[v]=u;last[v]=i;flow[v]=min(flow[u],e[i].flow);if(!inque[v]){q.push(v);inque[v]=1;}}}}if(pre[t]!=-1)return true;return false;
}
int maxflow,mincost;
void mcmf(int s,int t){while(spfa(s,t)){int u=t;
// printf("maxflow==%d %d %d\n",maxflow,flow[t],flow[t]*dis[t]);maxflow+=flow[t];mincost+=flow[t]*dis[t];while(u!=s){e[last[u]].flow-=flow[t];e[last[u]^1].flow+=flow[t];u=pre[u];}}return;
}
inline int id(int x,int y){return (x-1)*n+y;
}
signed main(){cin>>n>>k;m=n*n;int m2=2*m+n;int s=m*4+1;int t=m*4+2;int c;for(int i=1;i<=n;i++){for(int j=1;j<=n;j++){cin>>c;add_edge(id(i,j),id(i,j)+m,-c,1);add_edge(id(i,j),id(i,j)+m2,0,inf);}}for(int i=1;i<=n;i++){for(int j=1;j<=n;j++){if(j+1<=n){add_edge(id(i,j)+m,id(i,j+1),0,inf);add_edge(id(i,j)+m2,id(i,j+1),0,inf);}if(i+1<=n){add_edge(id(i,j)+m,id(i+1,j),0,inf);add_edge(id(i,j)+m2,id(i+1,j),0,inf);}}}add_edge(s,id(1,1),0,k);add_edge(id(n,n)+m,t,0,k);add_edge(id(n,n)+m2,t,0,k);mcmf(s,t);cout<<-mincost;return 0;
}
5.P2050 [NOI2012]美食节
在跑费用流的过程中,记录是哪个厨师被征用了,并记录这是这个厨师做的第几道菜,每条边的费用为边权∗time*time∗time,流量为1,
#include<bits/stdc++.h>
using namespace std;
const int inf=0x3f3f3f3f,maxn=3005,maxm=400005;
struct edge{int nex,v,cost,flow;
}e[maxm];
int head[maxn],cnt=1,tim[maxn],now,sum;
int n,m,k;
inline void add_edge(int u,int v,int cost,int flow){e[++cnt].v=v;e[cnt].cost=cost;e[cnt].flow=flow;e[cnt].nex=head[u];head[u]=cnt;e[++cnt].v=u;e[cnt].cost=-cost;e[cnt].flow=0;e[cnt].nex=head[v];head[v]=cnt;
}
int inque[maxn],dis[maxn],flow[maxn],pre[maxn],last[maxn];
bool spfa(int s,int t){queue<int>q;memset(dis,0x3f,sizeof dis);memset(flow,0x3f,sizeof flow);memset(inque,0,sizeof inque);q.push(s);inque[s]=1;dis[s]=0;pre[t]=-1;while(!q.empty()){int u=q.front();q.pop();inque[u]=0;for(int i=head[u];i;i=e[i].nex){int v=e[i].v;if(dis[v]>dis[u]+e[i].cost&&e[i].flow){dis[v]=dis[u]+e[i].cost;pre[v]=u;last[v]=i;flow[v]=min(flow[u],e[i].flow);if(!inque[v]){q.push(v);inque[v]=1;}}}}if(pre[t]!=-1)return true;return false;
}
int mp[maxn][maxn],p[maxn];
int jl[maxn];
inline pair<int,int> mcmf(int s,int t){int maxflow=0;int mincost=0;while(spfa(s,t)){int u=t;maxflow+=flow[t];mincost+=flow[t]*dis[t];int j=jl[pre[t]];
// printf("j==%d\n",j);tim[j]++;now++;for(int i=1;i<=n;i++){add_edge(i,now,mp[i][j]*tim[j],1);}add_edge(now,t,0,1);jl[now]=j;while(u!=s){e[last[u]].flow-=flow[t];e[last[u]^1].flow+=flow[t];u=pre[u];}}return {maxflow,mincost};
}
inline int id(int x,int y){return (x-1)*sum+y+sum;
}
int main(){cin>>n>>m;for(int i=1;i<=n;i++){cin>>p[i];sum+=p[i];}for(int i=1;i<=n;i++){for(int j=1;j<=m;j++){cin>>mp[i][j];}}int num=0;for(int i=1;i<=n;i++){for(int j=1;j<=m;j++){jl[j+sum]=j;add_edge(i,j+sum,mp[i][j],1);}}int s=sum+m+1;int t=sum+m+2;now=t;for(int i=1;i<=n;i++){add_edge(s,i,0,p[i]);}for(int i=1;i<=m;i++){tim[i]=1;add_edge(i+sum,t,0,1);}pair<int,int>yaoyao=mcmf(s,t);cout<<yaoyao.second;return 0;
}
6.P2053 [SCOI2007]修车
#include<bits/stdc++.h>
using namespace std;
const int inf=0x3f3f3f3f,maxn=3005,maxm=400005;
struct edge{int nex,v,cost,flow;
}e[maxm];
int head[maxn],cnt=1;
int n,m,k;
inline void add_edge(int u,int v,int cost,int flow){e[++cnt].v=v;e[cnt].cost=cost;e[cnt].flow=flow;e[cnt].nex=head[u];head[u]=cnt;e[++cnt].v=u;e[cnt].cost=-cost;e[cnt].flow=0;e[cnt].nex=head[v];head[v]=cnt;
}
int inque[maxn],dis[maxn],flow[maxn],pre[maxn],last[maxn];
bool spfa(int s,int t){queue<int>q;memset(dis,0x3f,sizeof dis);memset(flow,0x3f,sizeof flow);memset(inque,0,sizeof inque);q.push(s);inque[s]=1;dis[s]=0;pre[t]=-1;while(!q.empty()){int u=q.front();q.pop();inque[u]=0;for(int i=head[u];i;i=e[i].nex){int v=e[i].v;if(dis[v]>dis[u]+e[i].cost&&e[i].flow){dis[v]=dis[u]+e[i].cost;pre[v]=u;last[v]=i;flow[v]=min(flow[u],e[i].flow);if(!inque[v]){q.push(v);inque[v]=1;}}}}if(pre[t]!=-1)return true;return false;
}
inline pair<int,int> mcmf(int s,int t){int maxflow=0;int mincost=0;while(spfa(s,t)){int u=t;maxflow+=flow[t];mincost+=flow[t]*dis[t];while(u!=s){e[last[u]].flow-=flow[t];e[last[u]^1].flow+=flow[t];u=pre[u];}}return {maxflow,mincost};
}
int mp[maxn][maxn];
inline int id(int x,int y){return (x-1)*n+y+n;
}
int main(){cin>>m>>n;int s=n+n*m+1;int t=s+1;for(int i=1;i<=n;i++){for(int j=1;j<=m;j++){cin>>mp[i][j];}}for(int i=1;i<=n;i++){for(int j=1;j<=m;j++){for(int k=1;k<=n;k++){add_edge(i,id(j,k),mp[i][j]*k,1);}}}for(int i=1;i<=n;i++){add_edge(s,i,0,1);}for(int i=1;i<=n*m;i++){add_edge(i+n,t,0,1);}pair<int,int>yaoyao=mcmf(s,t);printf("%.2f",(double)yaoyao.second/n);return 0;
}
7.P2604 [ZJOI2010]网络扩容
先所有边费用为000跑一次费用流,加上带费用的边再跑一次流量为kkk的费用流即可
#include<bits/stdc++.h>
using namespace std;
const int inf=0x3f3f3f3f,maxn=20005,maxm=400005;
struct edge{int nex,v,cost,flow;
}e[maxm];
int head[maxn],cnt=1;
int n,m,k;
inline void add_edge(int u,int v,int cost,int flow){e[++cnt].v=v;e[cnt].cost=cost;e[cnt].flow=flow;e[cnt].nex=head[u];head[u]=cnt;e[++cnt].v=u;e[cnt].cost=-cost;e[cnt].flow=0;e[cnt].nex=head[v];head[v]=cnt;
}
int inque[maxn],dis[maxn],flow[maxn],pre[maxn],last[maxn];
bool spfa(int s,int t){queue<int>q;memset(dis,0x3f,sizeof dis);memset(flow,0x3f,sizeof flow);memset(inque,0,sizeof inque);q.push(s);inque[s]=1;dis[s]=0;pre[t]=-1;while(!q.empty()){int u=q.front();q.pop();inque[u]=0;for(int i=head[u];i;i=e[i].nex){int v=e[i].v;if(dis[v]>dis[u]+e[i].cost&&e[i].flow){dis[v]=dis[u]+e[i].cost;pre[v]=u;last[v]=i;flow[v]=min(flow[u],e[i].flow);if(!inque[v]){q.push(v);inque[v]=1;}}}}if(pre[t]!=-1)return true;return false;
}
inline pair<int,int> mcmf(int s,int t){int maxflow=0;int mincost=0;while(spfa(s,t)){int u=t;maxflow+=flow[t];mincost+=flow[t]*dis[t];while(u!=s){e[last[u]].flow-=flow[t];e[last[u]^1].flow+=flow[t];u=pre[u];}}return {maxflow,mincost};
}
int u[maxn],v[maxn],w[maxn];
int main(){cin>>n>>m>>k;for(int i=1;i<=m;i++){int c;scanf("%d%d%d%d",&u[i],&v[i],&c,&w[i]);add_edge(u[i],v[i],0,c);}pair<int,int>ans=mcmf(1,n);cout<<ans.first<<" ";add_edge(n,n+1,0,k);for(int i=1;i<=m;i++){add_edge(u[i],v[i],w[i],inf);}pair<int,int>yaoyao=mcmf(1,n+1);cout<<yaoyao.second;return 0;
}
8.P2770 航空路线问题
我本想用交换棋子那题一拆三一进一出这样的写,想直接一步到位,结果无限RERERE…
将所有的边全部转化为 西边->东边的单向边,最西和最东的点流量限制为2,其他点全部为1,拆点的费用全为-1
#include<bits/stdc++.h>
using namespace std;
typedef pair<int,int> pii;
const int inf=0x3f3f3f3f,maxn=40005,maxm=400005;
struct edge{int nex,v,cost,flow;
}e[maxm];
int head[maxn],cnt=1;
int n,m,k,T;
inline void add_edge(int u,int v,int cost,int flow){e[++cnt].v=v;e[cnt].cost=cost;e[cnt].flow=flow;e[cnt].nex=head[u];head[u]=cnt;e[++cnt].v=u;e[cnt].cost=-cost;e[cnt].flow=0;e[cnt].nex=head[v];head[v]=cnt;
}
int inque[maxn],dis[maxn],flow[maxn],pre[maxn],last[maxn];
bool spfa(int s,int t){queue<int>q;memset(dis,0x3f,sizeof dis);memset(flow,0x3f,sizeof flow);memset(inque,0,sizeof inque);q.push(s);inque[s]=1;dis[s]=0;pre[t]=-1;while(!q.empty()){int u=q.front();q.pop();inque[u]=0;for(int i=head[u];i;i=e[i].nex){int v=e[i].v;if(dis[v]>dis[u]+e[i].cost&&e[i].flow){dis[v]=dis[u]+e[i].cost;pre[v]=u;last[v]=i;flow[v]=min(flow[u],e[i].flow);if(!inque[v]){q.push(v);inque[v]=1;}}}}if(pre[t]!=-1)return true;return false;
}
string str[105];
unordered_map<string,int>mp;
inline pair<int,int> mcmf(int s,int t){int maxflow=0;int mincost=0;int tim=0;while(spfa(s,t)){int u=t;maxflow+=flow[t];mincost+=flow[t]*dis[t];++tim;while(u!=s){e[last[u]].flow-=flow[t];e[last[u]^1].flow+=flow[t];u=pre[u];}}return {maxflow,mincost};
}
int vis[1005];
vector<string>jl1,jl2;
void dfs1(int u){jl1.push_back(str[u]);
// cout<<str[u]<<endl;vis[u]=1;for(int i=head[u+n];i;i=e[i].nex){int v=e[i].v;if(e[i].flow!=0||vis[v]==1||v>n||v<1)continue;else{dfs1(v);break;}}
}
void dfs2(int u){// vis[u]=1;jl2.push_back(str[u]);for(int i=head[u+n];i;i=e[i].nex){int v=e[i].v;if(e[i].flow!=0||vis[v]==1||v>n||v<1)continue;dfs2(v);}
// cout<<str[u]<<endl;
}
int main(){cin>>n>>m;int num=0;int s=1;int t=n*2;bool ok=false;for(int i=1;i<=n;i++){string a;cin>>a;mp[a]=i;str[i]=a;if(i==1||i==n){add_edge(i,i+n,-1,2);}else{add_edge(i,i+n,-1,1);}}for(int i=1;i<=m;i++){string a,b;cin>>a>>b;int x=mp[a];int y=mp[b];if(x>y)swap(x,y);if(x==1&&y==n)ok=true;add_edge(x+n,y,0,1);}
// add_edge(s,s+n,0,2);
// add_edge(n+n,t,0,2);pii yaoyao=mcmf(s,t);if(yaoyao.first==2){printf("%d\n",-yaoyao.second-2);dfs1(s);dfs2(s);for(auto v:jl1){cout<<v<<endl;}string zz[105];int numzz=0;for(auto v:jl2){zz[++numzz]=v;}for(int i=numzz;i>=1;i--){cout<<zz[i]<<endl;}}else if(yaoyao.first==1&&ok){cout<<2<<endl;cout<<str[1]<<endl;cout<<str[n]<<endl;cout<<str[1]<<endl;}else{printf("No Solution!");}return 0;}
9.P3159 [CQOI2012]交换棋子
然后这一点就有点骚了,因为每个格子有换的次数限制,然后起始点只会换一次,但是路上的点都会被换两次,我们必须要处理这个区别,咋办呢?一拆二好像并不能解决这个问题,所以
入点->原点,流量为tim/2tim/2tim/2,原点->出点 (tim+1)/2(tim+1)/2(tim+1)/2
入点->原点,流量为(tim+1)/2(tim+1)/2(tim+1)/2,原点->出点 tim/2tim/2tim/2
入点->原点,流量为tim/2tim/2tim/2,原点->出点 tim/2tim/2tim/2
统计移动次数,那自然是格子之间的连边费用为111,其他全为000,边间流量全为infinfinf
#include<bits/stdc++.h>
using namespace std;
const int inf=0x3f3f3f3f,maxn=20005,maxm=400005;
struct edge{int nex,v,cost,flow;
}e[maxm];
int head[maxn],cnt=1;
int n,m,k;
const int dx[]={1,1,1,-1,-1,-1,0,0};
const int dy[]={1,-1,0,1,-1,0,1,-1};
inline void add_edge(int u,int v,int cost,int flow){e[++cnt].v=v;e[cnt].cost=cost;e[cnt].flow=flow;e[cnt].nex=head[u];head[u]=cnt;e[++cnt].v=u;e[cnt].cost=-cost;e[cnt].flow=0;e[cnt].nex=head[v];head[v]=cnt;
}
int inque[maxn],dis[maxn],flow[maxn],pre[maxn],last[maxn];
bool spfa(int s,int t){queue<int>q;memset(dis,0x3f,sizeof dis);memset(flow,0x3f,sizeof flow);memset(inque,0,sizeof inque);q.push(s);inque[s]=1;dis[s]=0;pre[t]=-1;while(!q.empty()){int u=q.front();q.pop();inque[u]=0;for(int i=head[u];i;i=e[i].nex){int v=e[i].v;if(dis[v]>dis[u]+e[i].cost&&e[i].flow){dis[v]=dis[u]+e[i].cost;pre[v]=u;last[v]=i;flow[v]=min(flow[u],e[i].flow);if(!inque[v]){q.push(v);inque[v]=1;}}}}if(pre[t]!=-1)return true;return false;
}
inline pair<int,int> mcmf(int s,int t){int maxflow=0;int mincost=0;while(spfa(s,t)){int u=t;maxflow+=flow[t];mincost+=flow[t]*dis[t];while(u!=s){e[last[u]].flow-=flow[t];e[last[u]^1].flow+=flow[t];u=pre[u];}}return {maxflow,mincost};
}
inline int id1(int x,int y){return (x-1)*m+y;
}
inline int id2(int x,int y){return (x-1)*m+y+n*m;
}
inline int id3(int x,int y){return (x-1)*m+y+n*m*2;
}
char mp1[25][25],mp2[25][25],mp3[25][25];
int u[maxn],v[maxn],w[maxn];
int main(){cin>>n>>m;int s=n*m*3+1;int t=n*m*3+2;int cc=0;for(int i=1;i<=n;i++){for(int j=1;j<=m;j++){cin>>mp1[i][j];if(mp1[i][j]=='1')add_edge(s,id2(i,j),0,1),cc++;}}for(int i=1;i<=n;i++){for(int j=1;j<=m;j++){cin>>mp2[i][j];if(mp2[i][j]=='1')add_edge(id2(i,j),t,0,1);}}for(int i=1;i<=n;i++){for(int j=1;j<=m;j++){cin>>mp3[i][j];int tim=mp3[i][j]-'0';if(mp1[i][j]==mp2[i][j]){add_edge(id1(i,j),id2(i,j),0,tim/2);add_edge(id2(i,j),id3(i,j),0,tim/2);}if(mp1[i][j]=='1'&&mp2[i][j]=='0'){add_edge(id1(i,j),id2(i,j),0,tim/2);add_edge(id2(i,j),id3(i,j),0,(tim+1)/2);}if(mp1[i][j]=='0'&&mp2[i][j]=='1'){add_edge(id1(i,j),id2(i,j),0,(tim+1)/2);add_edge(id2(i,j),id3(i,j),0,tim/2);}}}for(int i=1;i<=n;i++){for(int j=1;j<=m;j++){for(int k=0;k<8;k++){int xx=dx[k]+i;int yy=dy[k]+j;if(xx>=1&&xx<=n&&yy<=m&&yy>=1){add_edge(id3(i,j),id1(xx,yy),1,inf);}}}}pair<int,int>yaoyao=mcmf(s,t);int ans=yaoyao.first;
// cout<<ans<<" ";if(ans==cc)cout<<yaoyao.second;else cout<<"-1";return 0;
}
10.P3356 火星探险问题
重点在于输出路径,这里需要用到边的流量的性质,正向边走过的流量就在反向边上加上了,我们可以由此来判断每个点被多少条路线走过,dfsdfsdfs记录走过每个点的次数,每次与反向边的流量比较即可
#include<bits/stdc++.h>
using namespace std;
typedef pair<int,int> pii;
const int inf=0x3f3f3f3f,maxn=20005,maxm=400005;
struct edge{int nex,v,cost,flow;
}e[maxm];
int head[maxn],cnt=1;
int n,m,k,T;
inline void add_edge(int u,int v,int cost,int flow){e[++cnt].v=v;e[cnt].cost=cost;e[cnt].flow=flow;e[cnt].nex=head[u];head[u]=cnt;e[++cnt].v=u;e[cnt].cost=-cost;e[cnt].flow=0;e[cnt].nex=head[v];head[v]=cnt;
}
int inque[maxn],dis[maxn],flow[maxn],pre[maxn],last[maxn];
bool spfa(int s,int t){queue<int>q;memset(dis,0x3f,sizeof dis);memset(flow,0x3f,sizeof flow);memset(inque,0,sizeof inque);q.push(s);inque[s]=1;dis[s]=0;pre[t]=-1;while(!q.empty()){int u=q.front();q.pop();inque[u]=0;for(int i=head[u];i;i=e[i].nex){int v=e[i].v;if(dis[v]>dis[u]+e[i].cost&&e[i].flow){dis[v]=dis[u]+e[i].cost;pre[v]=u;last[v]=i;flow[v]=min(flow[u],e[i].flow);if(!inque[v]){q.push(v);inque[v]=1;}}}}if(pre[t]!=-1)return true;return false;
}
inline pair<int,int> mcmf(int s,int t){int maxflow=0;int mincost=0;while(spfa(s,t)){int u=t;maxflow+=flow[t];mincost+=flow[t]*dis[t];while(u!=s){e[last[u]].flow-=flow[t];e[last[u]^1].flow+=flow[t];u=pre[u];}}return {maxflow,mincost};
}
inline int id(int x,int y){return (x-1)*m+y;
}
inline int id2(int x,int y){return (x-1)*m+y+n*m;
}
int vis[maxn];
void dfs(int u,int num){for(int i=head[u+n*m];i;i=e[i].nex){int v=e[i].v;if(v==u+1&&vis[i]<e[i^1].flow){printf("%d 1\n",num);vis[i]++;dfs(v,num);break;}if(v==u+m&&vis[i]<e[i^1].flow){printf("%d 0\n",num);vis[i]++;dfs(v,num);break;}}
}
int mp[105][105];
int main(){cin>>k>>m>>n;for(int i=1;i<=n;i++){for(int j=1;j<=m;j++){cin>>mp[i][j];if(mp[i][j]==1)continue;add_edge(id(i,j),id2(i,j),mp[i][j]==2?-1:0,1);add_edge(id(i,j),id2(i,j),0,inf);}}int s=n*m*2+1;int t=s+1;if(mp[1][1]!=1)add_edge(s,id(1,1),0,k);if(mp[n][m]!=1)add_edge(id2(n,m),t,0,k);for(int i=1;i<=n;i++){for(int j=1;j<=m;j++){if(mp[i][j]==1)continue;if(mp[i][j+1]!=1&&j+1<=m){add_edge(id2(i,j),id(i,j+1),0,inf);}if(mp[i+1][j]!=1&&i+1<=n){add_edge(id2(i,j),id(i+1,j),0,inf);}}}pii yaoyao=mcmf(s,t);for(int i=1;i<=k;i++){dfs(1,i);}return 0;
}
11.P3358 最长k可重区间集问题
12.P4013 数字梯形问题
task1:task1:task1:不允许有路径相交:
很简单,一看就是点和边流量限制都为1,这样就不可能有右边的流跨到左边去了
task2:task2:task2:允许选重复的点:
点的流量限制无限即可,主要点跟汇点的流量也要改掉
task3:task3:task3:允许路径相交,允许重复点:
点边都无限即可
#include<bits/stdc++.h>
using namespace std;
typedef pair<int,int> pii;
const int inf=0x3f3f3f3f,maxn=40005,maxm=400005;
struct edge{int nex,v,cost,flow;
}e[maxm];
int head[maxn],cnt=1;
int n,m,k,T;
inline void add_edge(int u,int v,int cost,int flow){e[++cnt].v=v;e[cnt].cost=cost;e[cnt].flow=flow;e[cnt].nex=head[u];head[u]=cnt;e[++cnt].v=u;e[cnt].cost=-cost;e[cnt].flow=0;e[cnt].nex=head[v];head[v]=cnt;
}
int inque[maxn],dis[maxn],flow[maxn],pre[maxn],last[maxn];
bool spfa(int s,int t){queue<int>q;memset(dis,0x3f,sizeof dis);memset(flow,0x3f,sizeof flow);memset(inque,0,sizeof inque);q.push(s);inque[s]=1;dis[s]=0;pre[t]=-1;while(!q.empty()){int u=q.front();q.pop();inque[u]=0;for(int i=head[u];i;i=e[i].nex){int v=e[i].v;if(dis[v]>dis[u]+e[i].cost&&e[i].flow){dis[v]=dis[u]+e[i].cost;pre[v]=u;last[v]=i;flow[v]=min(flow[u],e[i].flow);if(!inque[v]){q.push(v);inque[v]=1;}}}}if(pre[t]!=-1)return true;return false;
}
inline pair<int,int> mcmf(int s,int t){int maxflow=0;int mincost=0;while(spfa(s,t)){int u=t;maxflow+=flow[t];mincost+=flow[t]*dis[t];while(u!=s){e[last[u]].flow-=flow[t];e[last[u]^1].flow+=flow[t];u=pre[u];}}return {maxflow,mincost};
}
inline int id(int x,int y){return (x-1)*(m+n-1)+y;
}
int mp[1000][1000];
int main(){cin>>m>>n;int num=10000;int k=m-1;int s=20001;int t=20002;for(int i=1;i<=n;i++){k++;for(int j=1;j<=k;j++){cin>>mp[i][j];add_edge(id(i,j),id(i,j)+num,-mp[i][j],1);if(i==1){add_edge(s,id(i,j),0,1);}if(i==n){add_edge(id(i,j)+num,t,0,1);}}}k=m-1;for(int i=1;i<=n-1;i++){k++;for(int j=1;j<=k;j++){add_edge(id(i,j)+num,id(i+1,j),0,1);add_edge(id(i,j)+num,id(i+1,j+1),0,1);}}pii yaoyao1=mcmf(s,t);cout<<-yaoyao1.second<<endl;memset(head,0,sizeof head);cnt=1;for(int i=1;i<=n;i++){k++;for(int j=1;j<=k;j++){// cin>>mp[i][j];add_edge(id(i,j),id(i,j)+num,-mp[i][j],inf);if(i==1){add_edge(s,id(i,j),0,1);}if(i==n){add_edge(id(i,j)+num,t,0,inf);}}}k=m-1;for(int i=1;i<=n-1;i++){k++;for(int j=1;j<=k;j++){add_edge(id(i,j)+num,id(i+1,j),0,1);add_edge(id(i,j)+num,id(i+1,j+1),0,1);}}pii yaoyao2=mcmf(s,t);cout<<-yaoyao2.second<<endl;memset(head,0,sizeof head);cnt=1;for(int i=1;i<=n;i++){k++;for(int j=1;j<=k;j++){// cin>>mp[i][j];add_edge(id(i,j),id(i,j)+num,-mp[i][j],inf);if(i==1){add_edge(s,id(i,j),0,1);}if(i==n){add_edge(id(i,j)+num,t,0,inf);}}}k=m-1;for(int i=1;i<=n-1;i++){k++;for(int j=1;j<=k;j++){add_edge(id(i,j)+num,id(i+1,j),0,inf);add_edge(id(i,j)+num,id(i+1,j+1),0,inf);}}pii yaoyao3=mcmf(s,t);cout<<-yaoyao3.second<<endl;return 0;
}
13.P4015 运输问题
#include<bits/stdc++.h>
using namespace std;
typedef pair<int,int> pii;
const int inf=0x3f3f3f3f,maxn=40005,maxm=400005;
struct edge{int nex,v,cost,flow;
}e[maxm];
int head[maxn],cnt=1;
int n,m,k,T;
inline void add_edge(int u,int v,int cost,int flow){e[++cnt].v=v;e[cnt].cost=cost;e[cnt].flow=flow;e[cnt].nex=head[u];head[u]=cnt;e[++cnt].v=u;e[cnt].cost=-cost;e[cnt].flow=0;e[cnt].nex=head[v];head[v]=cnt;
}
int inque[maxn],dis[maxn],flow[maxn],pre[maxn],last[maxn];
bool spfa(int s,int t){queue<int>q;memset(dis,0x3f,sizeof dis);memset(flow,0x3f,sizeof flow);memset(inque,0,sizeof inque);q.push(s);inque[s]=1;dis[s]=0;pre[t]=-1;while(!q.empty()){int u=q.front();q.pop();inque[u]=0;for(int i=head[u];i;i=e[i].nex){int v=e[i].v;if(dis[v]>dis[u]+e[i].cost&&e[i].flow){dis[v]=dis[u]+e[i].cost;pre[v]=u;last[v]=i;flow[v]=min(flow[u],e[i].flow);if(!inque[v]){q.push(v);inque[v]=1;}}}}if(pre[t]!=-1)return true;return false;
}
unordered_map<string,int>mp;
inline pair<int,int> mcmf(int s,int t){int maxflow=0;int mincost=0;while(spfa(s,t)){int u=t;maxflow+=flow[t];mincost+=flow[t]*dis[t];while(u!=s){e[last[u]].flow-=flow[t];e[last[u]^1].flow+=flow[t];u=pre[u];}}return {maxflow,mincost};
}
inline int id(int i,int j){return (i-1)*n+j;
}
int a[50005],b[50005],x[50005];
int main(){cin>>m>>n;int s=n+m+1;int t=n+m+2;for(int i=1;i<=m;i++){scanf("%d",&a[i]);add_edge(s,i,0,a[i]);}for(int i=1;i<=n;i++){scanf("%d",&b[i]);add_edge(i+m,t,0,b[i]);}for(int i=1;i<=m;i++){for(int j=1;j<=n;j++){scanf("%d",&x[id(i,j)]);add_edge(i,j+m,x[id(i,j)],a[i]);}}pii yaoyao=mcmf(s,t);cout<<yaoyao.second<<endl;cnt=1;memset(head,0,sizeof head);for(int i=1;i<=m;i++){add_edge(s,i,0,a[i]);}for(int i=1;i<=n;i++){add_edge(i+m,t,0,b[i]);}for(int i=1;i<=m;i++){for(int j=1;j<=n;j++){add_edge(i,j+m,-x[id(i,j)],a[i]);}}pii yaoyao2=mcmf(s,t);cout<<-yaoyao2.second<<endl;return 0;
}
14.P5331 [SNOI2019]通信
能力提升综合题单Part 8.9.3 费用流相关推荐
- 洛谷 能力提升综合题单Part1 入门阶段 P1089 津津的储蓄计划 带注释
题目描述 津津的零花钱一直都是自己管理.每个月的月初妈妈给津津300300元钱,津津会预算这个月的花销,并且总能做到实际花销和预算的相同. 为了让津津学习如何储蓄,妈妈提出,津津可以随时把整百的钱存在 ...
- 刷题总结——支线剧情(bzoj3876费用流)
题目: [故事背景] 宅男JYY非常喜欢玩RPG游戏,比如仙剑,轩辕剑等等.不过JYY喜欢的并不是战斗场景,而是类似电视剧一般的充满恩怨情仇的剧情.这些游戏往往 都有很多的支线剧情,现在JYY想花费最 ...
- 线性规划与网络流24题 运输问题(最裸的费用流了)
存费用流模板 用sfpa算出最小费用和路径,沿这条路径增广 1 const 2 inf=maxlongint; 3 var 4 n,m:longint; 5 map,a,w:array[0..120, ...
- [网络流24题][CODEVS1916]负载平衡问题(费用流)
题目描述 传送门 题解 首先拆点,分XiYi,对应每个仓库. 从源点向Xi连边,容量为ri,费用为0: 从Yi向汇点连边,容量为xba,费用为0: 从Xi向对应的Yi连边,容量为INF,费用为0: 从 ...
- [网络流24题][CODEVS1237]餐巾计划问题(费用流)
题目描述 传送门 题解 拆点,把每天的点拆成xi和yi,xi表示每一天的脏毛巾,yi表示每一天的新毛巾. 从超级源向xi连边,容量为ri,费用为0: 从yi向超级汇连边,容量为ri,费用为0: 从超级 ...
- 辣鸡HellPix刷yyb网络流题单(orz yyb)
题目 评价 状态 [USACO4.2]草地排水Drainage Ditches(最大流) 最大流模板 Accepted HDU 3416 Marriage Match IV(最短路,网络流) 最小 ...
- 蔡丹红老师刁酒集团《基层管理人员综合能力提升培训班》企业内训开讲
蔡丹红老师:刁酒集团<基层管理人员综合能力提升培训班>企业内训开讲 一线员工总是奋斗在前线,为公司打开销路.打开渠道,为公司创造业绩,作为基层管理人员应做好本职工作,努力提升自己,提高综合 ...
- 软件技术专业大学生该如何制定职业综合能力提升计划
记得那还是五年级的时候,那时班主任叫我们写上自己的理想吧.我就记得自己写了成为一个对社会有用的人,而别的同学都写上科学家和老师等等.但随着不断的成长,我们都走上了自己特定的人生轨道.这个时候我们不能再 ...
- 《大数据实践课》开创实践教学新模式:清华大数据能力提升项目特色课程系列报道之一
2014年4月,清华大学顺应时代潮流成为全国第一批成立大数据研究机构的高等学府.四年来,清华-青岛数据科学研究院(以下简称:数据院)与研究生院共同设计组织实施了以大数据能力提升项目为主的大数据人才培养 ...
- 计算机网络技术综合题大全
第1章 计算机网络概述 一.简答题 1.简述计算机网络的发展过程. 答:从1946年世界上第一台计算机ENIAC的诞生到现在网络的全面普及,计算机网络的发展大体可以分为以下4个阶段: (1)第一代计算 ...
最新文章
- mirna富集分析_2020年的3+分ceRNA分析长啥样?
- epplus保存为流_c# – 另存为使用EPPlus?
- 转[WinForm] VS2010发布、打包安装程序(超全超详细)
- 如何使用Restic Backup Client将数据备份到对象存储服务
- 设计模式(七)装饰模式
- easyui table 如何只展示一条_如何使用MySQL,这些操作你得明白!
- 调试程序Bug-陈棚
- win11怎么退回win7 Windows11退回win7的步骤方法
- 红警2 csf文件解析 简体化
- 文字转语音怎么真人发声
- 音频格式转换器哪个好,推荐几款免费的mp3格式转换器
- 7天从代码入门到开发应用,怎样快速提高代码能力?
- 1674386-82-3,Lipoamido-PEG2-alcohol醇基可以反应进一步衍生化合物
- 论文笔记 Object-Aware Instance Labeling for Weakly Supervised Object Detection - ICCV 2019
- Tower of Hanoi (汉诺塔问题)
- idea插件 之~~~~mybatisx(忍者鸟)、lombox(小辣椒)
- AppScan使用教程
- 页面加载时,vue生命周期的触发顺序
- cass怎么添加指北针图例_怎么才能在excel中把表格做的好看?
- Hive中ORDER BY、SORT BY和DISTRIBUTE BY
热门文章
- php中的条件语句,PHP中的条件语句和示例
- java怎么返回string_黄瓜Java-如何在下一步中使用返回的String?
- python多进程优化_python多进程提高cpu利用率
- python分布式爬虫_python-分布式爬虫
- python 复制列表内容_python 复制列表的六种方法
- 磁盘上没有足够的空间完成此操作_Win10硬盘怎么分区?Win10系统下新建磁盘分区图解教程...
- PAT之查找:遍历、二分、hash
- nyoj 236 心急的C小加(贪心)
- nyoj810 贪心的嘿嘿(想弄死这出题的)
- 服务器位置设置,服务器部署位置