网络流与线性规划 24 题
网络流与线性规划 24 题
1. P2764 最小路径覆盖问题 (紫)
建图方式
把每个点拆成两个节点,此时的最大流对应的就是最多可以合并的路径数。
路径输出直接在残余网络上跑
#include<bits/stdc++.h>
using namespace std;
const int MX_M=6100,MX_N=300;
struct node{
int next,to;
int w;
}edge[MX_M<<1];
int head[MX_N]={0},edge_cnt=0;
inline void add(int x,int y,int w){
node &i=edge[edge_cnt];
i.next=head[x],i.to=y,i.w=w;
head[x]=edge_cnt++;
}
int s,t,n,m,input_n;
int dist[MX_N]={0};
bool bfs(){
memset(dist,-1,sizeof(dist));
queue<int > qu;
qu.push(s);dist[s]=0;
while(!qu.empty()){
int now=qu.front();qu.pop();
for(int i=head[now];i!=-1;i=edge[i].next){
int to=edge[i].to;
if(dist[to]==-1&&edge[i].w){
dist[to]=dist[now]+1;
qu.push(to);
}
}
}
return dist[t]!=-1;
}
int cur[MX_N]={0};
int dfs(int now,int flow){
if(now==t) return flow;
int left=flow;
for(int &i=cur[now];i!=-1;i=edge[i].next){
int to=edge[i].to,w=edge[i].w;
if(dist[to]==dist[now]+1&&w){
int cur_flow=dfs(to,min(left,w));
left-=cur_flow;
edge[i].w-=cur_flow;
edge[i^1].w+=cur_flow;
if(left==0) break;
}
}
if(left==flow) dist[now]=-1;
return flow-left;
}
vector<int >vec[MX_N];
bool vis[MX_N]={0};
void dfs2(int now){
vis[now]=1;
for(auto to:vec[now]){
if(vis[to]==0) dfs2(to);
}
printf("%d ",now);
return ;
}
signed main(){
memset(head,-1,sizeof(head));
scanf("%d%d",&input_n,&m);
n=2+2*input_n;
/*
s=1
si=i+1;
t=2+2*input_n;
ti=input_n+1+i
*/
s=1,t=2+2*input_n;n=t;
for(int i=1;i<=input_n;i++){
add(s,i+1,1);
add(i+1,s,0);
}
for(int i=1;i<=input_n;i++){
add(input_n+i+1,t,1);
add(t,input_n+i+1,0);
}
for(int i=1;i<=m;i++){
int x,y;scanf("%d%d",&x,&y);
add(x+1,input_n+y+1,1);
add(input_n+y+1,x+1,0);
}
int ans_max=0;
while(bfs()){
for(int i=1;i<=n;i++) cur[i]=head[i];
ans_max+=dfs(s,0x3f3f3f3f);
}
int ans=input_n-ans_max;
for(int i=1;i<=n;i++){
for(int j=head[i];j!=-1;j=edge[j].next){
if(i>=2&&i<=1+input_n&&edge[j].to>=input_n+2&&edge[j].to<=1+input_n+input_n&&!edge[j].w){
vec[i-1].push_back(edge[j].to-input_n-1);
vec[edge[j].to-input_n-1].push_back(i-1);
}
}
}
for(int i=1;i<=input_n;i++){
if(vis[i]==0) dfs2(i),printf("\n");
}
printf("%d",ans);
return 0;
}
2. P2763 试题库问题 (蓝)
建图方式
#include<bits/stdc++.h>
using namespace std;
const int MX_N=5010,MX_M=5010000;
struct node{
int to,next,w;
}edge[MX_M<<1];
int head[MX_N]={0},edge_cnt=0;
inline void add(int x,int y,int w){
auto &i=edge[edge_cnt];
i.w=w;i.to=y;i.next=head[x];
head[x]=edge_cnt++;
}
int s,t,n;
int cur[MX_N]={0};
int dist[MX_N]={0};
bool bfs(){
for(int i=1;i<=n+10;i++) dist[i]=-1;
dist[s]=0;queue<int > qu;qu.push(s);
while(!qu.empty()){
int now=qu.front();qu.pop();
for(int i=head[now];i!=-1;i=edge[i].next){
int to=edge[i].to;
if(dist[to]==-1&&edge[i].w){
dist[to]=dist[now]+1;
qu.push(to);
}
}
}
return dist[t]!=-1;
}
int dfs(int now,int flow){
if(now==t) return flow;
int left=flow;
for(int &i=cur[now];i!=-1;i=edge[i].next){
int to=edge[i].to,w=edge[i].w;
if(dist[to]==dist[now]+1&&w){
int cur_flow=dfs(to,min(w,left));
left-=cur_flow;
edge[i].w-=cur_flow;
edge[i^1].w+=cur_flow;
if(left==0) break;
}
}
if(left==flow) dist[now]=-1;
return flow-left;
}
int input_n,k;
void print(int x,int y,int w){ //输出边
if(x==1) printf("s ");
if(x>=2&&x<=1+input_n) printf("n%d ",x-1);
if(x>=2+input_n&&x<=1+input_n+k) printf("k%d ",x-1-input_n);
if(x==n) printf("t ");
if(y==1) printf("s ");
if(y>=2&&y<=1+input_n) printf("n%d ",y-1);
if(y>=2+input_n&&y<=1+input_n+k) printf("k%d ",y-1-input_n);
if(y==n) printf("t ");
printf(" %d",w);
printf("\n");
}
vector<int > vec[30];
signed main(){
memset(head,-1,sizeof(head));
int inm_m=0;
scanf("%d%d",&k,&input_n);
s=1,t=2+input_n+k;
for(int i=1;i<=k;i++){
int ki;scanf("%d",&ki);inm_m+=ki;
add(i+input_n+1,t,ki);
add(t,i+input_n+1,0);
}
for(int i=1;i<=input_n;i++){
add(s,i+1,1);
add(i+1,s,0);
}
for(int i=1;i<=input_n;i++){
int p;scanf("%d",&p);
for(int j=1;j<=p;j++){
int ki;scanf("%d",&ki);
add(i+1,input_n+ki+1,1);
add(input_n+ki+1,i+1,0);
}
}
n=2+input_n+k;
int ans=0;
while(bfs()){
for(int i=1;i<=n;i++) cur[i]=head[i];
ans+=dfs(s,0x3f3f3f3f);
}
if(ans!=inm_m){ printf("No Solution!");return 0;}
for(int now=1;now<=n;now++){
for(int i=head[now];i!=-1;i=edge[i].next){
int to=edge[i].to,w=edge[i].w;
if(now>=2&&now<=1+input_n&&to>=2+input_n&&to<=1+input_n+k && !w){
// print(now,to,w);
int x,y;
x=now-1,y=to-1-input_n;
vec[y].push_back(x);
}
}
}
for(int i=1;i<=k;i++){
printf("%d: ",i);
for(auto j:vec[i]){
printf("%d ",j);
}
printf("\n");
}
return 0;
}
3. P3254 圆桌问题 (蓝)
建图方式
每个单位与每个餐桌建一条边
#include<bits/stdc++.h>
using namespace std;
const int MX_N=5010,MX_M=5010000;
struct node{
int to,next,w;
}edge[MX_M<<1];
int head[MX_N]={0},edge_cnt=0;
inline void Add(int x,int y,int w){
auto &i=edge[edge_cnt];
i.w=w;i.to=y;i.next=head[x];
head[x]=edge_cnt++;
}
int s,t,n;
int cur[MX_N]={0};
int dist[MX_N]={0};
bool bfs(){
for(int i=1;i<=n+10;i++) dist[i]=-1;
dist[s]=0;queue<int > qu;qu.push(s);
while(!qu.empty()){
int now=qu.front();qu.pop();
for(int i=head[now];i!=-1;i=edge[i].next){
int to=edge[i].to;
if(dist[to]==-1&&edge[i].w){
dist[to]=dist[now]+1;
qu.push(to);
}
}
}
return dist[t]!=-1;
}
int dfs(int now,int flow){
if(now==t) return flow;
int left=flow;
for(int &i=cur[now];i!=-1;i=edge[i].next){
int to=edge[i].to,w=edge[i].w;
if(dist[to]==dist[now]+1&&w){
int cur_flow=dfs(to,min(w,left));
left-=cur_flow;
edge[i].w-=cur_flow;
edge[i^1].w+=cur_flow;
if(left==0) break;
}
}
if(left==flow) dist[now]=-1;
return flow-left;
}
inline void add(int x,int y,int w){
Add(x,y,w),Add(y,x,0);
}
signed main(){
memset(head,-1,sizeof(head));
int m,input_n;scanf("%d%d",&m,&input_n);
int sumn=0;
s=1,t=2+m+input_n;n=t;
for(int i=1;i<=m;i++){
int ri;scanf("%d",&ri);sumn+=ri;
add(s,1+i,ri);
}
for(int i=1;i<=input_n;i++){
int ci;scanf("%d",&ci);
add(1+m+i,t,ci);
}
for(int i=1;i<=m;i++){
for(int j=1;j<=input_n;j++){
int x=1+i,y=1+m+j;
add(x,y,1);
}
}
int ans=0;
while(bfs()){
for(int i=1;i<=n;i++) cur[i]=head[i];
ans+=dfs(s,0x3f3f3f3f);
}
if(sumn!=ans){printf("0");return 0;}
printf("1\n");
for(int i=1;i<=m;i++){
for(int j=head[i+1];j!=-1;j=edge[j].next){
int to=edge[j].to;
if(to>=2+m&&to<=1+m+input_n&&edge[j].w==0){
printf("%d ",to-1-m);
}
}
printf("\n");
}
return 0;
}
4. P2756 飞行员配对方案问题(蓝)
建图方式
无
普通的二分图匹配
#include<bits/stdc++.h>
using namespace std;
const int MX_N=310,MX_M=11000;
struct node{
int next,to,w;
}edge[MX_M<<1];
int edge_cnt=0,head[MX_N]={0};
inline void Add(int x,int y,int w){
node &i=edge[edge_cnt];
i.w=w,i.to=y,i.next=head[x];
head[x]=edge_cnt++;
}
inline void add(int x,int y,int w){
Add(x,y,w),Add(y,x,0);
}
int cur[MX_N]={0},dist[MX_N]={0};
int n,s,t;
bool bfs(){
for(int i=1;i<=n;i++) dist[i]=-1,cur[i]=head[i];
queue<int >qu;dist[s]=0;qu.push(s);
while(!qu.empty()){
int now=qu.front();qu.pop();
for(int i=head[now];i!=-1;i=edge[i].next){
int to=edge[i].to;
if(dist[to]==-1&&edge[i].w){
dist[to]=dist[now]+1;
qu.push(to);
}
}
}
return dist[t]!=-1;
}
int dfs(int now,int flow){
if(now==t) return flow;
int left=flow;
for(int &i=cur[now];i!=-1;i=edge[i].next){
int to=edge[i].to,w=edge[i].w;
if(dist[to]==dist[now]+1&&w){
int cur_flow=dfs(to,min(w,left));
left-=cur_flow;
edge[i].w-=cur_flow;
edge[i^1].w+=cur_flow;
if(left==0) break;
}
}
if(left==flow) dist[now]=-1;
return flow-left;
}
signed main(){
memset(head,-1,sizeof(head));
int m,input_n;
scanf("%d%d",&m,&input_n);
int u=0,v=0;
s=1,t=input_n+2;n=t;
for(int i=m+1;i<=input_n;i++){
add(s,1+i,1);
}
for(int i=1;i<=m;i++){
add(i+1,t,1);
}
while(1){
scanf("%d%d",&u,&v);
if(u==-1&&v==-1) break;
add(v+1,u+1,1);
}
int ans=0;
while(bfs()){
ans+=dfs(s,0x3f3f3f3f);
}
printf("%d\n",ans);
for(int i=2;i<=m+1;i++){
for(int j=head[i];j!=-1;j=edge[j].next){
int to=edge[j].to,w=edge[j].w;
if(m+2<=to&&to<=input_n+1&&w){
printf("%d %d\n",i-1,to-1);
}
}
}
return 0;
}
5. P2754 [CTSC1999] 家园 / 星际转移问题(紫
)
建图方式
分层图,枚举天数,每次从前一天的残余网络上加边
#include<bits/stdc++.h>
using namespace std;
const int MX_N=22723,MX_M=101000,D=1050;
struct node{
int next,to,w;
}edge[MX_M<<1];
int head[MX_N]={0},edge_cnt=0;
int n,s,t;
int cur[MX_N]={0},dist[MX_N]={0};
bool bfs(){
for(int i=1;i<MX_N;i++) dist[i]=-1,cur[i]=head[i];
queue<int > qu;qu.push(s);dist[s]=0;
while(!qu.empty()){
int now=qu.front();qu.pop();
for(int i=head[now];i!=-1;i=edge[i].next){
int to=edge[i].to;
if(dist[to]==-1&&edge[i].w){
qu.push(to);dist[to]=dist[now]+1;
}
}
}
return dist[t]!=-1;
}
int dfs(int now,int flow){
if(now==t) return flow;
int left=flow;
for(int &i=cur[now];i!=-1;i=edge[i].next){
int to=edge[i].to,w=edge[i].w;
if(dist[to]==dist[now]+1&&w){
int cur_flow=dfs(to,min(left,w));
left-=cur_flow;
edge[i].w-=cur_flow;
edge[i^1].w+=cur_flow;
if(left==0) break;
}
}
if(left==flow) dist[now]=-1;
return flow-left;
}
int dinic(){
int ans=0;
while (bfs())
{
ans+=dfs(s,0x3f3f3f3f);
}
return ans;
}
inline void Add(int x,int y,int w){
node &i=edge[edge_cnt];
i.w=w,i.to=y,i.next=head[x];
head[x]=edge_cnt++;
}
inline void add(int x,int y,int w){
Add(x,y,w),Add(y,x,0);
}
short point[D+10][MX_N+10]={0};
int car[D+10][30]={0};//第i天m车在哪里
int h[30]={0};
int fath[20]={0};
int fx(int x){
if(x==fath[x]) return x;
return fath[x]=fx(fath[x]);
}
void cy(int x,int y){
if(rand()&1) swap(x,y);
fath[fx(x)]=fath[(fx(y))];
}
signed main(){
for(int i=1;i<20;i++) fath[i]=i;
memset(head,-1,sizeof(head));
int input_n,m,k;
scanf("%d%d%d",&input_n,&m,&k);
int sn=0;
for(int i=0;i<=D;i++){
for(int j=0;j<=input_n+1;j++){
point[i][j]=++sn;
}
}
for(int i=1;i<=m;i++){
int pi,r;scanf("%d%d",&pi,&r);
h[i]=pi;
for(int j=0;j<r;j++){
int si;scanf("%d",&si);
if(si==-1) si=input_n+1;
for(int k=0;k*r+j<=D;k++){
car[k*r+j][i]=si;
}
cy(car[0][i],si);
}
}
if(fx(0)!=fx(input_n+1)){
printf("0");
return 0;
}
s=sn+10,t=s+1;n=t;
add(s,point[0][0],k);
int ans=0,sum=0;
while(1){
ans++;
for(int i=0;i<=input_n+1;i++){
add(point[ans-1][i],point[ans][i],0x3f3f3f3f);
}
add(point[ans][input_n+1],t,0x3f3f3f3f);
for(int i=1;i<=m;i++){
add(point[ans-1][car[ans-1][i]],point[ans][car[ans][i]],h[i]);
}
sum+=dinic();
if(sum>=k) break;
}
printf("%d",ans);
return 0;
}
6. P2766 最长不下降子序列问题(紫)
拆点
建图方式
主要是求第三个值的修改方式不一样对吧
总结:将原图的 某条边的值由
可这是建立在原图的这两个点之间有边的情况下,
如果原图没有这两个点之间的边,你去加
#include<bits/stdc++.h>
using namespace std;
const int MX_N=1200,MX_M=251500*2;
struct node{
int to,next,w;
}edge[MX_M<<1];
int head[MX_N]={0},edge_cnt=0;
inline void Add(int x,int y,int w){
node &i=edge[edge_cnt];
i.w=w,i.to=y,i.next=head[x];
head[x]=edge_cnt++;
}
inline void add(int x,int y,int w){
Add(x,y,w),Add(y,x,0);
}
int s,t;
int cur[MX_N]={0},dist[MX_N]={0};
bool bfs(){
for(int i=1;i<MX_N;i++) cur[i]=head[i],dist[i]=-1;
queue<int > qu;qu.push(s);dist[s]=0;
while(!qu.empty()){
int now=qu.front();qu.pop();
for(int i=head[now];i!=-1;i=edge[i].next){
int to=edge[i].to;
if(dist[to]==-1&&edge[i].w){
dist[to]=dist[now]+1;
qu.push(to);
}
}
}
return dist[t]!=-1;
}
int dfs(int now,int flow){
if(now==t) return flow;
int left=flow;
for(int &i=cur[now];i!=-1;i=edge[i].next){
int to=edge[i].to,w=edge[i].w;
if(dist[to]==dist[now]+1&&w){
int cur_flow=dfs(to,min(left,w));
left-=cur_flow;
edge[i].w-=cur_flow;
edge[i^1].w+=cur_flow;
if(left==0) break;
}
}
if(flow==left) dist[now]=-1;
return flow-left;
}
int dinic(){
int sum=0;
while(bfs()){
sum+=dfs(s,0x3f3f3f3f);
}
return sum;
}
int input[MX_N]={0},dp[MX_N]={0};
signed main(){
memset(head,-1,sizeof(head));
//=======================================================
int n;scanf("%d",&n);
s=n*2+1,t=s+1;
for(int i=1;i<=n;i++) scanf("%d",input+i);
int maxn=1;
for(int i=1;i<=n;i++){
dp[i]=1;
for(int j=1;j<i;j++){
if(input[j]<=input[i]){
dp[i]=max(dp[i],dp[j]+1);
}
}
for(int j=1;j<i;j++){
if(input[j]<=input[i]&&dp[j]+1==dp[i]){
add(n+j,i,1);
}
}
if(dp[i]==1) add(s,i,1);
maxn=max(maxn,dp[i]);
}
for(int i=1;i<=n;i++){
if(dp[i]==maxn){
add(i+n,t,1);
}
add(i,i+n,1);
}
printf("%d\n",maxn);
if(maxn==1){
printf("%d\n%d",n,n);return 0;
}
int ans=dinic();
printf("%d\n",ans);
add(s,1,0x3f3f3f3f);
add(1,n+1,0x3f3f3f3f);
add(n,n+n,0x3f3f3f3f);
if(dp[n]==maxn) add(n+n,t,0x3f3f3f3f); //关键,如果原来没有这一条边就不能建
printf("%d",ans+dinic());
//=======================================================
return 0;
}
7. P2774 方格取数问题(紫)
建图方式
六倍经验P2774 P3410 P3355 P4304 P5030 P4474
#include<bits/stdc++.h>
using namespace std;
const int MX_N=50100,MX_M=5010000;
struct node{
int next,to,w;
}edge[MX_M];
int edge_cnt=0,head[MX_N]={0};
inline void Add(int x,int y,int w){
node &i=edge[edge_cnt];
i.to=y,i.w=w,i.next=head[x];
head[x]=edge_cnt++;
}
inline void add(int x,int y,int w){
Add(x,y,w),Add(y,x,0);
}
int cur[MX_N]={0},dist[MX_N]={0};
int s,t;
bool bfs(){
for(int i=0;i<MX_N;i++) dist[i]=-1,cur[i]=head[i];
dist[s]=0;queue<int >qu;qu.push(s);
while(!qu.empty()){
int now=qu.front();qu.pop();
for(int i=head[now];~i;i=edge[i].next){
int to=edge[i].to,w=edge[i].w;
if(dist[to]==-1&&w){
dist[to]=dist[now]+1;
qu.push(to);
}
}
}
return dist[t]!=-1;
}
int dfs(int now,int flow){
if(now==t) return flow;
int left=flow;
for(int &i=cur[now];~i;i=edge[i].next){
int to=edge[i].to,w=edge[i].w;
if(dist[to]==dist[now]+1&&w){
int cur_flow=dfs(to,min(left,w));
left-=cur_flow;
edge[i].w-=cur_flow;
edge[i^1].w+=cur_flow;
if(left==0) break;
}
}
if(left==flow) dist[now]=-1;
return flow-left;
}
int dinic(){
int sum=0;
while(bfs()) sum+=dfs(s,0x3f3f3f3f);
return sum;
}
int mapn[200][200]={0};
int fx[5]={0,1,0,-1,0};
int fy[5]={0,0,1,0,-1};
int n,m;
inline bool check(int x,int y){
return x>=1&&x<=n&&y>=1&&y<=m;
}
inline int has(int x,int y){
return (x-1)*m+y;
}
signed main(){
memset(head,-1,sizeof(head));
scanf("%d%d",&n,&m);
s=0,t=n*m+10;int sum=0;
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++){
scanf("%d",&mapn[i][j]);sum+=mapn[i][j];
if((i+j)%2==0){
add(s,has(i,j),mapn[i][j]);
}
else{
add(has(i,j),t,mapn[i][j]);
}
}
}
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++){
for(int k=1;k<=4;k++){
int dx=i+fx[k],dy=j+fy[k];
if(check(dx,dy)&&(i+j)%2==0){
add(has(i,j),has(dx,dy),0x3f3f3f3f);
}
}
}
}
printf("%d",sum-dinic());
return 0;
}
8. P3355 骑士共存问题 (紫)
建图方式
#include<bits/stdc++.h>
using namespace std;
const long long MX_N=41000,MX_M=510000;
struct node{
long long to,next,w;
}edge[MX_M<<1];
long long head[MX_N]={0},edge_cnt=0;
inline void Add(long long x,long long y,long long w){
node &i=edge[edge_cnt];
i.w=w,i.to=y,i.next=head[x];
head[x]=edge_cnt++;
}
inline void add(long long x,long long y,long long w){
Add(x,y,w),Add(y,x,0);
}
long long s=0,t=MX_N-1;
long long cur[MX_N]={0},dist[MX_N]={0};
bool bfs(){
for(long long i=0;i<MX_N;i++) cur[i]=head[i],dist[i]=-1;
queue<long long > qu;qu.push(s);dist[s]=0;
while(!qu.empty()){
long long now=qu.front();qu.pop();
for(long long i=head[now];i!=-1;i=edge[i].next){
long long to=edge[i].to;
if(dist[to]==-1&&edge[i].w){
dist[to]=dist[now]+1;
qu.push(to);
}
}
}
return dist[t]!=-1;
}
long long dfs(long long now,long long flow){
if(now==t) return flow;
long long left=flow;
for(long long &i=cur[now];i!=-1;i=edge[i].next){
long long to=edge[i].to,w=edge[i].w;
if(dist[to]==dist[now]+1&&w){
long long cur_flow=dfs(to,min(left,w));
left-=cur_flow;
edge[i].w-=cur_flow;
edge[i^1].w+=cur_flow;
if(left==0) break;
}
}
if(flow==left) dist[now]=-1;
return flow-left;
}
long long dinic(){
long long sum=0;
while(bfs()){
sum+=dfs(s,0x3f3f3f3f);
}
return sum;
}
long long n,m;
long long mapn[210][210]={0};
inline long long has(long long x,long long y){
return (x-1)*n+y;
}
inline bool check(long long x,long long y){
return x>=1&&x<=n&&y>=1&&y<=n&&mapn[x][y]==0;
}
long long sn=0;
long long fx[9]={0,1,1,-1,-1,2,2,-2,-2},fy[9]={0,2,-2,2,-2,1,-1,1,-1};
signed main(){
memset(head,-1,sizeof(head));
//============================================================
scanf("%lld%lld",&n,&m);
for(long long i=1;i<=m;i++){
long long x,y;scanf("%lld%lld",&x,&y);
mapn[x][y]=1;
}
for(long long i=1;i<=n;i++){
for(long long j=1;j<=n;j++){
if(mapn[i][j]) continue;
if((i+j)%2==0){
add(s,has(i,j),1);
for(long long k=1;k<=8;k++){
long long dx=i+fx[k],dy=j+fy[k];
if(check(dx,dy)){
add(has(i,j),has(dx,dy),0x3f3f3f3f);
}
}
}
else{
add(has(i,j),t,1);
}
}
}
printf("%lld",n*n-m-dinic());
//===========================================================
return 0;
}
9. P2762 太空飞行计划问题 (紫)
建图方式
#include<bits/stdc++.h>
using namespace std;
const int MX_N=410,MX_M=6100;
const int INF=0x3f3f3f3f;
struct node{
int to,next,w;
}edge[MX_M<<1];
int head[MX_N]={0},edge_cnt=0;
inline void Add(int x,int y,int w){
node &i=edge[edge_cnt];
i.w=w,i.to=y,i.next=head[x];
head[x]=edge_cnt++;
}
inline void add(int x,int y,int w){
Add(x,y,w),Add(y,x,0);
}
int s=0,t=MX_N-1;
int cur[MX_N]={0},dist[MX_N]={0};
bool bfs(){
for(int i=0;i<MX_N;i++) cur[i]=head[i],dist[i]=-1;
queue<int > qu;qu.push(s);dist[s]=0;
while(!qu.empty()){
int now=qu.front();qu.pop();
for(int i=head[now];i!=-1;i=edge[i].next){
int to=edge[i].to;
if(dist[to]==-1&&edge[i].w){
dist[to]=dist[now]+1;
qu.push(to);
}
}
}
return dist[t]!=-1;
}
int dfs(int now,int flow){
if(now==t) return flow;
int left=flow;
for(int &i=cur[now];i!=-1;i=edge[i].next){
int to=edge[i].to,w=edge[i].w;
if(dist[to]==dist[now]+1&&w){
int cur_flow=dfs(to,min(left,w));
left-=cur_flow;
edge[i].w-=cur_flow;
edge[i^1].w+=cur_flow;
if(left==0) break;
}
}
if(flow==left) dist[now]=-1;
return flow-left;
}
int dinic(){
int sum=0;
while(bfs()){
sum+=dfs(s,INF);
}
return sum;
}
int read() {
static char c;
static int x;
if(c == '\n') return c = 0, -1;
while(!isdigit(c = getchar()));
x = c ^ 48;
while(isdigit(c = getchar()))
x = x * 10 + (c ^ 48);
return x;
}
bool st[MX_N]={0};
void dfs1(int now){
st[now]=1;
for(int i=head[now];~i;i=edge[i].next){
int to=edge[i].to,w=edge[i].w;
if(st[to]==0&&w) dfs1(to);
}
}
signed main() {
memset(head,-1,sizeof(head));
int m,n;int sum=0;
scanf("%d %d", &m, &n);
for(int i = 1; i <= m; i++) {
int x;
scanf("%d", &x);add(s,i,x);sum+=x;
while(~(x = read())) add(i,x+m,INF);
}
for(int i = 1; i <= n; i++){int x;
scanf("%d", &x);add(i+m,t,x);
}
sum-=dinic();
dfs1(s);
for(int i=1;i<=m;i++) if(st[i]) printf("%d ",i);
printf("\n");
for(int i=m+1;i<=m+n;i++) if(st[i]) printf("%d ",i-m);
printf("\n");
printf("%d",sum);
return 0;
}
10. P4015 运输问题
建图方式
最小费用最大流和最大费用最大流。
构图:
源点 向 每一个仓库连接一条流量为
仓库
销售点
跑一个
第二个任务只要清空图,然后重新连接为费用是
#include<bits/stdc++.h>
using namespace std;
const int MX_N=5010,MX_M=50100;
const int INF=0x3f3f3f3f;
struct node{
int next,to;
int w,c;
}edge[MX_M<<1];
int head[MX_N]={0},edge_cnt=0;
inline void Add(int x,int y,int w,int c){
node &i=edge[edge_cnt];
i.w=w,i.c=c,i.to=y,i.next=head[x];
head[x]=edge_cnt++;
}
inline void add(int x,int y,int w,int c){
Add(x,y,w,c);Add(y,x,0,-c);
}
int dist[MX_N]={0},lim[MX_N]={0},pre[MX_N]={0};
bool vis[MX_N]={0};
int s=0,t=MX_N-1;
bool spfa(){
memset(dist,INF,sizeof(dist));
memset(lim,0,sizeof(lim));
memset(vis,0,sizeof(vis));
queue<int >qu;
qu.push(s);vis[s]=1,lim[s]=INF,dist[s]=0;
while(!qu.empty()){
int now=qu.front();qu.pop();vis[now]=0;
for(int i=head[now];~i;i=edge[i].next){
int to=edge[i].to,w=edge[i].w,c=edge[i].c;
if(dist[to]>dist[now]+c&&w){
dist[to]=dist[now]+c;
lim[to]=min(lim[now],w);
pre[to]=i;
if(!vis[to]){
qu.push(to);
vis[to]=1;
}
}
}
}
return lim[t]>0;
}
void EK(int &flow,int &cost){
flow=cost=0;
while(spfa()){
flow+=lim[t];
cost+=lim[t]*dist[t];
for(int i=t;i!=s;i=edge[pre[i]^1].to){
edge[pre[i]].w-=lim[t];
edge[pre[i]^1].w+=lim[t];
}
}
}
signed main(){
memset(head,-1,sizeof(head));
//=======================================
int m,n;scanf("%d%d",&m,&n);
for(int i=1;i<=m;i++){
int xi;scanf("%d",&xi);
add(s,i,xi,0);
}
for(int i=1;i<=n;i++){
int xi;scanf("%d",&xi);
add(i+m,t,xi,0);
}
for(int i=1;i<=m;i++){
for(int j=1;j<=n;j++){
int xi;scanf("%d",&xi);
add(i,j+m,INF,xi);
}
}
int flow,cost;EK(flow,cost);
printf("%d\n",cost);
for(int i=0;i<edge_cnt;i++){
edge[i].c=-edge[i].c;
}
for(int i=0;i<edge_cnt;i+=2){
edge[i].w+=edge[i^1].w;
edge[i^1].w=0;
}
EK(flow,cost);
printf("%d",-cost);
//=======================================
return 0;
}
11. P4016 负载平衡问题
建图方式
建一个源点
每个要运出货物的仓库与
每个要运入货物的仓库与
仓库之间依次连容量为
跑一遍费用流即可
#include<bits/stdc++.h>
using namespace std;
const int MX_N=5010,MX_M=50100;
const int INF=0x3f3f3f3f;
struct node{
int next,to;
int w,c;
}edge[MX_M<<1];
int head[MX_N]={0},edge_cnt=0;
inline void Add(int x,int y,int w,int c){
node &i=edge[edge_cnt];
i.w=w,i.c=c,i.to=y,i.next=head[x];
head[x]=edge_cnt++;
}
inline void add(int x,int y,int w,int c){
Add(x,y,w,c),Add(y,x,0,-c);
}
int dist[MX_N]={0},lim[MX_N]={0},pre[MX_N]={0};
bool vis[MX_N]={0};
int s=0,t=MX_N-1;
bool spfa(){
memset(dist,INF,sizeof(dist));
memset(lim,0,sizeof(lim));
memset(vis,0,sizeof(vis));
queue<int > qu;
qu.push(s);vis[s]=1;dist[s]=0;lim[s]=INF;
while(!qu.empty()){
int now=qu.front();qu.pop();vis[now]=0;
for(int i=head[now];~i;i=edge[i].next){
int to=edge[i].to,w=edge[i].w,c=edge[i].c;
if(dist[to]>dist[now]+c&&w){
dist[to]=dist[now]+c;
lim[to]=min(lim[now],w);
pre[to]=i;
if(!vis[to]){
qu.push(to);
vis[to]=1;
}
}
}
}
return lim[t]>0;
}
void EK(int &flow,int &cost){
flow=cost=0;
while(spfa()){
flow+=lim[t];
cost+=lim[t]*dist[t];
for(int i=t;i!=s;i=edge[pre[i]^1].to){
edge[pre[i]].w-=lim[t];
edge[pre[i]^1].w+=lim[t];
}
}
}
int a[MX_N]={0};
int n;
inline int prem(int now){
now--;
if(now==0) return n;
return now;
}
inline int nex(int now){
now++;
if(now==n+1) return 1;
return now;
}
signed main(){
memset(head,-1,sizeof(head));
scanf("%d",&n);int sum=0;
for(int i=1;i<=n;i++){
scanf("%d",&a[i]);sum+=a[i];
}
sum/=n;
for(int i=1;i<=n;i++){
if(a[i]>sum){
add(s,i,a[i]-sum,0);
}
else{
add(i,t,sum-a[i],0);
}
}
for(int i=1;i<=n;i++){
add(i,prem(i),INF,1);
add(i,nex(i),INF,1);
}
int flow,cost;EK(flow,cost);
printf("%d",cost);
return 0;
}
12. P4014 分配问题
建图方式
非常裸的二分图最佳完美匹配。
无图
#include<bits/stdc++.h>
using namespace std;
const int MX_N=5010,MX_M=50100;
const int INF=0x3f3f3f3f;
struct node{
int next,to;
int w,c;
}edge[MX_M<<1];
int head[MX_N]={0},edge_cnt=0;
inline void Add(int x,int y,int w,int c){
node &i=edge[edge_cnt];
i.w=w,i.c=c,i.to=y,i.next=head[x];
head[x]=edge_cnt++;
}
inline void add(int x,int y,int w,int c){
Add(x,y,w,c);Add(y,x,0,-c);
}
int dist[MX_N]={0},lim[MX_N]={0},pre[MX_N]={0};
bool vis[MX_N]={0};
int s=0,t=MX_N-1;
bool spfa(){
memset(dist,INF,sizeof(dist));
memset(lim,0,sizeof(lim));
memset(vis,0,sizeof(vis));
queue<int >qu;
qu.push(s);vis[s]=1,lim[s]=INF,dist[s]=0;
while(!qu.empty()){
int now=qu.front();qu.pop();vis[now]=0;
for(int i=head[now];~i;i=edge[i].next){
int to=edge[i].to,w=edge[i].w,c=edge[i].c;
if(dist[to]>dist[now]+c&&w){
dist[to]=dist[now]+c;
lim[to]=min(lim[now],w);
pre[to]=i;
if(!vis[to]){
qu.push(to);
vis[to]=1;
}
}
}
}
return lim[t]>0;
}
void EK(int &flow,int &cost){
flow=cost=0;
while(spfa()){
flow+=lim[t];
cost+=lim[t]*dist[t];
for(int i=t;i!=s;i=edge[pre[i]^1].to){
edge[pre[i]].w-=lim[t];
edge[pre[i]^1].w+=lim[t];
}
}
}
signed main(){
memset(head,-1,sizeof(head));
//=======================================
int n,m;scanf("%d",&n);m=n;
for(int i=1;i<=m;i++){
add(s,i,1,0);
}
for(int i=1;i<=n;i++){
add(i+m,t,1,0);
}
for(int i=1;i<=m;i++){
for(int j=1;j<=n;j++){
int xi;scanf("%d",&xi);
add(i,j+m,INF,xi);
}
}
int flow,cost;EK(flow,cost);
printf("%d\n",cost);
for(int i=0;i<edge_cnt;i++){
edge[i].c=-edge[i].c;
}
for(int i=0;i<edge_cnt;i+=2){
edge[i].w+=edge[i^1].w;
edge[i^1].w=0;
}
EK(flow,cost);
printf("%d",-cost);
//=======================================
return 0;
}
13. P4013 数字梯形问题
建图方式
#include<bits/stdc++.h>
using namespace std;
const long long MX_N=20100,MX_M=31000;
const long long INF=0x3f3f3f3f;
struct node{
long long next,to;
long long w,c;
}edge[MX_M<<1];
long long head[MX_N]={0},edge_cnt=0;
inline void Add(long long x,long long y,long long w,long long c){
node &i=edge[edge_cnt];
i.to=y,i.w=w,i.c=c,i.next=head[x];
head[x]=edge_cnt++;
}
inline void add(long long x,long long y,long long w,long long c){
Add(x,y,w,c),Add(y,x,0,-c);
}
long long dist[MX_N]={0},lim[MX_N]={0},pre[MX_N]={0};
bool vis[MX_N]={0};
long long s=0,t=MX_N-1;
bool spfa(){
memset(dist,INF,sizeof(dist));memset(lim,0,sizeof(lim));memset(vis,0,sizeof(vis));
queue<long long >qu;qu.push(s);
vis[s]=1,lim[s]=INF,dist[s]=0;
while(!qu.empty()){
long long now=qu.front();qu.pop();vis[now]=0;
for(long long i=head[now];~i;i=edge[i].next){
long long to=edge[i].to,w=edge[i].w,c=edge[i].c;
if(dist[to]>dist[now]+c&&w){
dist[to]=dist[now]+c;
pre[to]=i;
lim[to]=min(lim[now],w);
if(!vis[to]){
qu.push(to);
vis[to]=1;
}
}
}
}
return lim[t]>0;
}
void EK(long long &flow,long long &cost){
flow=cost=0;
while(spfa()){
flow+=lim[t];
cost+=lim[t]*dist[t];
for(long long i=t;i!=s;i=edge[pre[i]^1].to){
edge[pre[i]].w-=lim[t];
edge[pre[i]^1].w+=lim[t];
}
}
}
long long mapn[100][100]={0};
long long has[100][100]={0};
long long m,n,cnt=0;
void init(){
memset(head,-1,sizeof(head));
for(long long i=0;i<edge_cnt;i++){
edge[i]=(node){0,0,0,0};
}
}
signed main(){
init();
//=======================================
scanf("%lld%lld",&m,&n);
for(long long i=1;i<=n;i++){
for(long long j=1;j<=m+i-1;j++){
scanf("%lld",&mapn[i][j]);
has[i][j]=++cnt;
}
}
//1
for(long long i=1;i<=n;i++){
for(long long j=1;j<=m+i-1;j++){
add(has[i][j],has[i][j]+cnt,1,-mapn[i][j]);
}
}
for(long long i=1;i<n;i++){
for(long long j=1;j<=m+i-1;j++){
add(has[i][j]+cnt,has[i+1][j],1,0);
add(has[i][j]+cnt,has[i+1][j+1],1,0);
}
}
for(long long i=1;i<=m;i++){
add(s,has[1][i],1,0);
}
for(long long i=1;i<=m+n-1;i++){
add(has[n][i]+cnt,t,1,0);
}
long long flow,cost;EK(flow,cost);
printf("%lld\n",-cost);
init();
//2
for(long long i=1;i<=n;i++){
for(long long j=1;j<=m+i-1;j++){
add(has[i][j],has[i][j]+cnt,INF,-mapn[i][j]);
}
}
for(long long i=1;i<n;i++){
for(long long j=1;j<=m+i-1;j++){
add(has[i][j]+cnt,has[i+1][j],1,0);
add(has[i][j]+cnt,has[i+1][j+1],1,0);
}
}
for(long long i=1;i<=m;i++){
add(s,has[1][i],1,0);
}
for(long long i=1;i<=m+n-1;i++){
add(has[n][i]+cnt,t,INF,0);
}
EK(flow,cost);
printf("%lld\n",-cost);
init();
//3
for(long long i=1;i<=n;i++){
for(long long j=1;j<=m+i-1;j++){
add(has[i][j],has[i][j]+cnt,INF,-mapn[i][j]);
}
}
for(long long i=1;i<n;i++){
for(long long j=1;j<=m+i-1;j++){
add(has[i][j]+cnt,has[i+1][j],INF,0);
add(has[i][j]+cnt,has[i+1][j+1],INF,0);
}
}
for(long long i=1;i<=m;i++){
add(s,has[1][i],1,0);
}
for(long long i=1;i<=m+n-1;i++){
add(has[n][i]+cnt,t,INF,0);
}
EK(flow,cost);
printf("%lld\n",-cost);
init();
//=======================================
return 0;
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· 阿里巴巴 QwQ-32B真的超越了 DeepSeek R-1吗?
· 如何调用 DeepSeek 的自然语言处理 API 接口并集成到在线客服系统
· 【译】Visual Studio 中新的强大生产力特性
· 2025年我用 Compose 写了一个 Todo App