网络流与线性规划 24 题

网络流与线性规划 24 题

1. P2764 最小路径覆盖问题 (紫)

建图方式

把每个点拆成两个节点,此时的最大流对应的就是最多可以合并的路径数。

n最大流 即为最少路径数

路径输出直接在残余网络上跑 dfs

#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 最长不下降子序列问题(紫)

拆点

建图方式

主要是求第三个值的修改方式不一样对吧

总结:将原图的 某条边的值由 1 改成 INF 和 在之前的这条边存在的情况下再加一条 同样两个点之间的 INF 的边 是等效的

可这是建立在原图的这两个点之间有边的情况下,
如果原图没有这两个点之间的边,你去加 INF 了,那就破坏了逻辑

#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 运输问题

建图方式

最小费用最大流和最大费用最大流。
构图:

源点每一个仓库连接一条流量为ai,费用为0的边。

仓库i销售点j 连接一条流量为无穷大,费用为ci,j

销售点j汇点 连接一条流量为bi,费用为0的边

跑一个,轻松完成第一个任务。

第二个任务只要清空图,然后重新连接为费用是ci的边即可。

#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 负载平衡问题

建图方式

建一个源点 s 和汇点 t (他们又来了),

每个要运出货物的仓库与 s 连边,

每个要运入货物的仓库与 t 连边,容量为要运进/运出货物的数量,花费为 0

仓库之间依次连容量为 INF ,花费为 1 的边,

跑一遍费用流即可

#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;
}
posted @   是菜菜呀  阅读(23)  评论(1编辑  收藏  举报
相关博文:
阅读排行:
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· 阿里巴巴 QwQ-32B真的超越了 DeepSeek R-1吗?
· 如何调用 DeepSeek 的自然语言处理 API 接口并集成到在线客服系统
· 【译】Visual Studio 中新的强大生产力特性
· 2025年我用 Compose 写了一个 Todo App
点击右上角即可分享
微信分享提示