网络流24题!!!!

网1:飞行员匹配

题目链接:https://www.oj.swust.edu.cn/problem/show/1736

俩种做法:

/**********二分图匹配做法***********/
#include<bits/stdc++.h>
using namespace std;
const int M=102;
int n,m;
int e[M][M],match[M],used[M];
bool find(int u){
    for(int i=1;i<=m;i++){
        if(e[u][i]==1&&used[i]==0){
            used[i]=1;
            if(match[i]==0||find(match[i])){
                match[i]=u;
                return true;
            }
        }
    }
    return false;
}
int main(){
    scanf("%d%d",&m,&n);
    int x,y;
    while(~scanf("%d%d",&x,&y)){
        if(x==-1&&y==-1)
            break;

        e[x][y]=1;
        e[y][x]=1;
    }
//  if(m==n||m==0)

    int ans=0;
    for(int i=m+1;i<=n;i++){
        memset(used,0,sizeof(used));
        if(find(i))
            ans++;
    }
    if(ans==0)
        return puts("No Solution!"),0;
    printf("%d\n",ans);
    for(int i=1;i<=m;i++)
        if(match[i])
            printf("%d %d\n",i,match[i]);
    return 0;
}
/***************网络流**************/
#include<bits/stdc++.h>
using namespace std;
const int M=505;
int cur[M],deep[M],head[M],s,t,tot;
const int inf=0x3f3f3f3f;
struct node{
    int v,nextt,w;
}e[M*50];
void addedge(int u,int v,int w){
    e[tot].v=v;
    e[tot].w=w;
    e[tot].nextt=head[u];
    head[u]=tot++;
    e[tot].v=u;
    e[tot].w=0;
    e[tot].nextt=head[v];
    head[v]=tot++;
}
bool bfs(){
    memset(deep,0,sizeof(deep));
    queue<int>que;
    que.push(s);
    deep[s]=1;
    while(!que.empty()){
        int u=que.front();
        que.pop();
        for(int i=head[u];i!=-1;i=e[i].nextt){
            int v=e[i].v;
            if(e[i].w>0&&deep[v]==0){
                deep[v]=deep[u]+1;
                if(v==t)
                    return true;
                que.push(v);
            }
        }
    }
    return deep[t]==0?false:true;
}
int dfs(int u,int fl){
    if(u==t)
        return fl;
    int x=0,ans=0;
    for(int i=cur[u];i!=-1;i=e[i].nextt){
        int v=e[i].v;
        if(deep[u]+1==deep[v]&&e[i].w>0){
            x=dfs(v,min(fl-ans,e[i].w));
            e[i].w-=x;
            e[i^1].w+=x;
            if(e[i].w)
                cur[u]=i;
            ans+=x;
            if(ans==fl)
                return fl;
        }
    }
    if(ans==0)
        deep[u]=0;
    return ans;
}
int dinic(int n){
    int ans=0;
    while(bfs()){
        for(int i=0;i<=t;i++)
            cur[i]=head[i];
        ans+=dfs(s,inf);
    }
    return ans;
}
int main(){
    memset(head,-1,sizeof(head));
    int n,m;
    cin>>m>>n;
    s=0,t=n+1;
    for(int i=1;i<=m;i++){
        addedge(s,i,1);
    }
    for(int i=m+1;i<=n;i++){
        addedge(i,t,1);
    }
    int x,y;
    while(~scanf("%d%d",&x,&y)){
        if(x==-1&&y==-1)
            break;
        addedge(x,y,1);
    }
    int ans=dinic(t);
    if(ans==0)
        return puts("No Solution!"),0;
    printf("%d\n",ans);
    for(int i=m+1;i<=n;i++)
        for(int j=head[i];j!=-1;j=e[j].nextt)
            if(e[j].v!=t&&e[j].w==1)
                printf("%d %d\n",e[j].v,i);
    return 0;
}

网2:飞行员计划问题

题目链接:https://www.oj.swust.edu.cn/problem/show/1737

最大权闭合图(总的答案就是最小路径覆盖的答案)

从起点往每个权值为正的点建立一条边,容量为点权值。

每个权值为负的点往终点建立一条边,容量为权值的绝对值。

如果选A就必须选B 则就从A建立一条往B的边,容量为inf。

最大权闭合图的点就是从起点开始广搜,权值为0的点不走,能走到的点就是被选中的点。

dinic最后一次bfs的d数组正好可以用来判断这个条件。

#include<bits/stdc++.h>
using namespace std;
const int M=505;
const int inf=0x3f3f3f3f;
struct node{
    int v,w,nextt;
}e[M*50];
int head[M],cur[M],deep[M],s,t,tot;
bool bfs(){
    memset(deep,0,sizeof(deep));
    queue<int >que;
    que.push(s);
    deep[s]=1;
    while(!que.empty()){
        int u=que.front();
        que.pop();
        for(int i=head[u];i!=-1;i=e[i].nextt){
            int v=e[i].v;
            if(e[i].w>0&&deep[v]==0){
                deep[v]=deep[u]+1;
                if(v==t)
                    return true;;
                que.push(v);
            }
        }
    }
    return false;
}
int dfs(int u,int fl){
    if(u==t)
        return fl;
    int ans=0,x=0;
    for(int i=cur[u];i!=-1;i=e[i].nextt){
        int v=e[i].v;
        if(e[i].w>0&&deep[v]==deep[u]+1){
            x=dfs(v,min(e[i].w,fl-ans));
            e[i].w-=x;
            e[i^1].w+=x;
            if(e[i].w)
                cur[u]=i;

            ans+=x;
            if(ans==fl)
                return fl;
        }
    }
    if(ans==0)
        deep[u]=0;
    return ans;
}
int dinic(int n){
    int ans=0;
    while(bfs()){
        for(int i=0;i<=n;i++)
            cur[i]=head[i];
        ans+=dfs(s,inf);
    }
    return ans;
}
void addedge(int u,int v,int w){
    e[tot].v=v;
    e[tot].w=w;
    e[tot].nextt=head[u];
    head[u]=tot++;
    e[tot].v=u;
    e[tot].w=0;
    e[tot].nextt=head[v];
    head[v]=tot++;
}
void init(){
    memset(head,-1,sizeof(head));
    tot=0;
}
int main(){

    init();
    int m,n;
    cin>>m>>n;
    s=0,t=n+m+1;
    int sum=0;
    for(int i=1;i<=m;i++){
        int w;
        scanf("%d",&w);
        addedge(s,n+i,w);
        sum+=w;
        int x;
        char ch;
        while(true){
            scanf("%d%c",&x,&ch);
            addedge(n+i,x,inf);
            if(ch==‘\r‘||ch==‘\n‘)
                break;
        }
    }
    for(int i=1;i<=n;i++){
        int x;
        scanf("%d",&x);
        addedge(i,t,x);
    }
    sum-=dinic(t);

    for(int i=1;i<=m;i++){
        if(deep[n+i])
            printf("%d ",i);
    }
    putchar(‘\n‘);
    for(int i=1;i<=n;i++){
        if(deep[i])
            printf("%d ",i);
    }
    putchar(‘\n‘);

    printf("%d\n",sum);
    return 0;
}

3、最小路径覆盖问题

题目链接:https://loj.ac/problem/6002

最小路径覆盖问题模型,拆点做最大匹配,总点数减去最大流为需要的最少的边数

题目有建图方法

拆点意思是这样的,第i个点的流量流向第j个点时表示第i个点的下一个点是j点,剩下的没办法流向终点的点就是没有点能到它那里,说明这个点是边的起点,根据这个来递归可以用来查找答案方案。

#include<bits/stdc++.h>
using namespace std;
const int M=505;
const int inf=0x3f3f3f3f;
struct node{
    int v,nextt,w;
}e[M*50];
int head[M],book[M],cur[M],deep[M],s,t,tot,n;
inline int read(){
    int sum=0,x=1;
    char ch=getchar();
    while(ch<‘0‘||ch>‘9‘){
        if(ch==‘-‘)
            x=0;
        ch=getchar();
    }
    while(ch>=‘0‘&&ch<=‘9‘)
        sum=(sum<<1)+(sum<<3)+(ch^48),ch=getchar();
    return x?sum:-sum;
}
inline void write(int x){
    if(x<0)
        putchar(‘-‘),x=-x;
    if(x>9)
        write(x/10);
    putchar(x%10+‘0‘);
}
void addedge(int u,int v,int w){
    e[tot].v=v;
    e[tot].w=w;
    e[tot].nextt=head[u];
    head[u]=tot++;
    e[tot].v=u;
    e[tot].w=0;
    e[tot].nextt=head[v];
    head[v]=tot++;
}
bool bfs(){
    memset(deep,0,sizeof(deep));
    queue<int>que;
    que.push(s);
    deep[s]=1;
    while(!que.empty()){
        int u=que.front();
        que.pop();
        for(int i=head[u];i!=-1;i=e[i].nextt){
            int v=e[i].v;
            if(e[i].w>0&&deep[v]==0){
                deep[v]=deep[u]+1;
                if(v==t)
                    return true;
                que.push(v);
            }
        }
    }
    return deep[t]==0?false:true;
}
int dfs(int u,int fl){
    if(u==t)
        return fl;
    int ans=0,x=0;
    for(int i=cur[u];i!=-1;i=e[i].nextt){
        int v=e[i].v;
        if(e[i].w>0&&deep[v]==deep[u]+1){
            x=dfs(v,min(e[i].w,fl-ans));
            e[i].w-=x;
            e[i^1].w+=x;
            if(e[i].w)
                cur[u]=i;
            ans+=x;
            if(ans==fl)
                return ans;
        }
    }
    if(ans==0)
        deep[u]=0;
    return ans;
}
int dinic(int n){
    int ans=0;
    while(bfs()){
        for(int i=0;i<=n;i++)
            cur[i]=head[i];
        ans+=dfs(s,inf);
    }
    return ans;
}
void dfs2(int u,int &flag){
    int point=u+n;
    book[u]=1;
    for(int i=head[point];i!=-1;i=e[i].nextt){
        if(e[i].v!=t&&e[i].w==1){
            dfs2(e[i].v,flag);
        }
    }

    if(flag==1)
        flag=0;
    else
        putchar(‘ ‘);
    write(u);
}
void init(){
    tot=0;
    memset(head,-1,sizeof(head));
}
int main(){
    init();
    n=read();
    int m;
    m=read();
    s=0,t=(n<<1)+1;
    for(int i=1;i<=n;i++)
        addedge(s,i,1),addedge(i+n,t,1);
    while(m--){
        int x=read(),y=read();
        addedge(x,y+n,1);
    }
    int sum=n-dinic(t);
    for(int i=head[t];i!=-1;i=e[i].nextt){
        int flag=1;
        if(!book[e[i].v-n]&&e[i].w==1){
            dfs2(e[i].v-n,flag);
            puts("");
        }
    }
    for(int i=1;i<=n;i++)
        if(!book[i])
            write(i),putchar(‘\n‘);
    write(sum);
    putchar(‘\n‘);
    return 0;
}

4、魔术球问题

题目链接:https://www.oj.swust.edu.cn/problem/show/1739

网络流跑形成的每条链就是题目要求的管子
由此答案就是各个点形成网络流的最小路径覆盖

因为网络流是在残量网络流上跑的,所以我们每次加一个点进去,在把符合条件的边加上去

注意判断条件:for(i=1; i-ans<=n+1; i++)
当加到刚好超过给点的n时即为答案,I是网络流上的点(除起点,汇点外),ans是最大流;

然后输出方案那里/2的意思因为我每次建点都是健俩点,所以输出方案点数编号的时候对应的就是其1/2倍。

#include<bits/stdc++.h>
using namespace std;
const int M=11111;
const int inf=0x3f3f3f3f;
struct node
{
    int v,nextt,w;
}e[M*20];
int head[M],cur[M],deep[M],hei[M],y[M],book[M],s,t,tot,cnt;

inline int read(){
    int sum=0,sign=1;
    char ch=getchar();
    while(ch<‘0‘||ch>‘9‘){
        if(ch==‘-‘)
            sign=0;
        ch=getchar();
    }
    while(ch>=‘0‘&&ch<=‘9‘)
        sum=(sum<<1)+(sum<<3)+(ch^48),ch=getchar();
    return sign?sum:-sum;
}
inline void write(int f){
    if(f<0)
        putchar(‘-‘),f=-f;
    if(f>9)
        write(f/10);
    putchar(f%10+‘0‘);
}
bool bfs(){
    memset(deep,0,sizeof(deep));
    queue<int>que;
    que.push(s);
    deep[s]=1;
    while(!que.empty()){
        int u=que.front();
        que.pop();
        for(int i=head[u];~i;i=e[i].nextt){
            int v=e[i].v;
            if(e[i].w>0&&deep[v]==0){
                deep[v]=deep[u]+1;
                if(v==t)
                    return true;
                que.push(v);
            }
        }
    }
    return deep[t]==0?false:true;
}
int dfs(int u,int fl){
    if(u==t)
        return fl;
    int ans=0,p=0;
    for(int i=cur[u];~i;i=e[i].nextt){
        int v=e[i].v;
        if(deep[v]==deep[u]+1&&e[i].w>0){
            p=dfs(v,min(fl-ans,e[i].w));
            e[i].w-=p;
            e[i^1].w+=p;
            if(e[i].w)
                cur[u]=i;
            ans+=p;
            if(ans==fl)
                return fl;
        }
    }
    if(ans==0)
        deep[u]=0;
    return ans;
}
int dinic(int n){
    int ans=0;
    while(bfs())
    {
        for(int i=0;i<=n;i++)
            cur[i]=head[i];
        ans+=dfs(s,inf);
    }
    return ans;
}
void init(){
    memset(head,-1,sizeof(head));
    tot=0,cnt=2;
}
void addedge(int u,int v,int w){
    e[tot].v=v;
    e[tot].w=w;
    e[tot].nextt=head[u];
    head[u]=tot++;
    e[tot].v=u;
    e[tot].w=0;
    e[tot].nextt=head[v];
    head[v]=tot++;
}
void prin(int u2,int &flag){
    book[u2]=1;
    int u=y[u2];
    for(int i=head[u];~i;i=e[i].nextt){
        if(e[i].w==1&&e[i].v!=t)
            prin(e[i].v/2,flag);
    }
    if(flag)
        flag=0;
    else
        putchar(‘ ‘);
    write(u2);
}
int main(){
    init();
    int n=read();
    s=0,t=11110;
    int i,ans=0;
    for(i=1;i-ans<=n+1;i++){
        hei[i]=cnt++;
        y[i]=cnt++;
        addedge(s,hei[i],1);
        addedge(y[i],t,1);
        for(int j=1;j<i;j++){
            int l=sqrt(i+j);
            if(l*l==i+j){
                addedge(hei[j],y[i],1);
            }
        }
        ans+=dinic(t);
    }
    int sum=i-2;
    write(sum);
    putchar(‘\n‘);
    int flag=1;
    for(int i=head[t];~i;i=e[i].nextt){
        if(e[i].w==1&&!book[e[i].v/2]){
            flag=1;
            prin(e[i].v/2,flag);
            putchar(‘\n‘);
        }
    }
    for(int i=1;i<=sum;i++)
        if(!book[i])
            write(i),putchar(‘\n‘);
    return 0;

}

5、圆桌问题

题目链接:https://www.luogu.org/problemnew/show/P3254

建图问题:健超级源点s,超级汇点t
s向每个代表连一条边,容量为人数------1
每个代表向每个圆桌拆个点出来连,容量为1(代表要一个人)-----2
最后每个圆桌向超级汇点连边,容量为圆桌允许人数ci-----3
第一步的编号为:1~n;
第二步的编号为:n+1~n+n*m;
第三步的编号为:n+n*m+1~n+n*m+m;
所以t编号为n+n*m+m+1;
跑网络流看最大流等不等与代表总人数

然后就是输出方案:
因为有走过,所以邻接边为1(看代码应该看得懂)
输出答案的话就找那个限制流量的边,如果那个边走过了就说明这个点有用嘛,找一下输出就行。

#include<bits/stdc++.h>
using namespace std;
const int M=50005;
const int inf=0x3f3f3f3f;
struct node{
    int v,nextt,w;
}e[M*20];
int head[M],cur[M],deep[M],tot,s,t;
inline int read(){
    int sum=0,x=1;
    char ch=getchar();
    while(ch<‘0‘||ch>‘9‘){
        if(ch==‘-‘)
            x=0;
        ch=getchar();
    }
    while(ch>=‘0‘&&ch<=‘9‘)
        sum=(sum<<1)+(sum<<3)+(ch^48),ch=getchar();
    return x?sum:-sum;
}
inline void write(int x){
    if(x<0)
        putchar(‘-‘),x=-x;
    if(x>9)
        write(x/10);
    putchar(x%10+‘0‘);
}
void addedge(int u,int v,int w){
    e[tot].v=v;
    e[tot].w=w;
    e[tot].nextt=head[u];
    head[u]=tot++;
    e[tot].v=u;
    e[tot].w=0;
    e[tot].nextt=head[v];
    head[v]=tot++;
}
bool bfs(){
    memset(deep,0,sizeof(deep));
    deep[s]=1;
    queue<int>que;
    que.push(s);
    while(!que.empty()){
        int u=que.front();
        que.pop();
        for(int i=head[u];~i;i=e[i].nextt){
            int v=e[i].v;
            if(deep[v]==0&&e[i].w>0){
                deep[v]=deep[u]+1;
                if(v==t)
                    return true;
                que.push(v);
            }
        }
    }
    return deep[t]==0?false:true;
}
int dfs(int u,int fl){
    if(u==t)
        return fl;
    int ans=0,x=0;
    for(int i=cur[u];~i;i=e[i].nextt){
        int v=e[i].v;
        if(e[i].w>0&&deep[v]==deep[u]+1){
            x=dfs(v,min(fl-ans,e[i].w));
            e[i].w-=x;
            e[i^1].w+=x;
            if(e[i].w)
                cur[u]=i;
            ans+=x;
            if(ans==fl)
                return ans;
        }
    }
    if(ans==0)
        deep[u]=0;
    return ans;
}
int dinic(int n){
    int ans=0;
    while(bfs()){
        for(int i=0;i<=n;i++)
            cur[i]=head[i];
        ans+=dfs(s,inf);
    }
    return ans;
}
void init(){
    tot=0;
    memset(head,-1,sizeof(head));
}
vector<int>a[M];
int main(){
    init();
    int n=read(),m=read();
    s=0,t=n+n*m+m+1;
    int sum=0;
    for(int i=1;i<=n;i++){
        int x=read();
        sum+=x;
        addedge(s,i,x);
    }
    for(int i=1;i<=n;i++){
        for(int j=1;j<=m;j++){
            addedge(i,n+(i-1)*m+j,1);
            addedge(n+(i-1)*m+j,n+n*m+j,1);
        }
    }
    for(int i=1;i<=m;i++){
        int x=read();
        addedge(n+n*m+i,t,x);
    }
    if(dinic(t)==sum){
        puts("1");
    }
    else
        return puts("0"),0;
    //cout<<"!!"<<endl;
    for(int i=1;i<=m;i++){
        for(int j=head[n+n*m+i];~j;j=e[j].nextt){
            if(e[j].v!=t&&e[j].w==1){
                a[(e[j].v-n-i)/m+1].push_back(i);
            }
        }
    }
    for(int i=1;i<=n;i++){
        write(a[i][0]);
        for(int j=1;j<a[i].size();j++)
            putchar(‘ ‘),write(a[i][j]);
        putchar(‘\n‘);
    }
    return 0;
}

6、最长递增子序列问题

题目链接:https://www.luogu.org/problemnew/show/P2766

第一问就用nlogn的dp去做,然后第二问第三问就用dp过程来模拟走网络流过程,建图也是如此;

将每个点拆点边权为1(代表只能用一次),然后其他看代码建图应该能懂;

第三问特殊地要求x1和xn可以重复使用,只需取消这两个点相关边的流量限制,求网络最大流即可。

#include<bits/stdc++.h>
using namespace std;
const int M=805;
const int  inf=0x3f3f3f3f;
struct node{
    int v,nextt,w;
}e[20005];
int head[20005],cur[20005],deep[20005],s,t,tot,a[M],dp[M];
void init(){
    tot=0;
    memset(head,-1,sizeof(head));
}
void addedge(int u,int v,int w){
    e[tot].v=v;
    e[tot].w=w;
    e[tot].nextt=head[u];
    head[u]=tot++;
    e[tot].v=u;
    e[tot].w=0;
    e[tot].nextt=head[v];
    head[v]=tot++;
}
bool bfs(){
    memset(deep,0,sizeof(deep));
    queue<int>que;
    que.push(s);
    deep[s]=1;
    while(!que.empty()){
        int u=que.front();
        que.pop();
        for(int i=head[u];~i;i=e[i].nextt){
            int v=e[i].v;
            if(deep[v]==0&&e[i].w>0){
                deep[v]=deep[u]+1;
                if(v==t)
                    return true;
                que.push(v);
            }
        }
    }
    return deep[t]==0?false:true;
}
int dfs(int u,int fl){
    if(u==t)
        return fl;
    int x=0,ans=0;
    for(int i=cur[u];~i;i=e[i].nextt){
        int v=e[i].v;
        if(deep[v]==deep[u]+1&&e[i].w>0){
            x=dfs(v,min(fl-ans,e[i].w));
            e[i].w-=x;
            e[i^1].w+=x;
            if(e[i].w)
                cur[u]=i;
            ans+=x;
            if(ans==fl)
                return ans;
        }
    }
    if(ans==0)
        deep[u]=0;
    return ans;
}
int dinic(int n){
    int ans=0;
    while(bfs()){
        for(int i=0;i<=n;i++)
            cur[i]=head[i];
        ans+=dfs(s,inf);
    }
    return ans;
}
int main(){
    int n;
    scanf("%d",&n);
    s=0,t=n*2+1;
    init();
    for(int i=1;i<=n;i++){
        scanf("%d",&a[i]);
        dp[i]=1;
    }
    for(int i=1;i<=n;i++)
        for(int j=1;j<i;j++)
            if(a[i]>=a[j])
                dp[i]=max(dp[j]+1,dp[i]);
    int ans=0;
    for(int i=1;i<=n;i++){
        ans=max(ans,dp[i]);
    }
    for(int i=1;i<=n;i++)
        if(dp[i]==ans)
            addedge(s,i,1);

    for(int i=1;i<=n;i++)
        addedge(i+n,i,1);

    for(int i=1;i<=n;i++)
        if(dp[i]==1)
            addedge(i,t,1);

    for(int i=1;i<=n;i++)
        for(int j=1;j<i;j++)
            if(a[i]>=a[j]&&dp[i]==dp[j]+1)
                addedge(i,j+n,1);
    int c=dinic(t);
    printf("%d\n%d\n",ans,c);
    if(dp[n]==ans)
        addedge(s,n,inf);
    addedge(1+n,1,inf);
    addedge(1,t,inf);
    c+=dinic(t);
    printf("%d\n",c);
    return 0;
}

7、试题库问题

题目链接:https://www.luogu.org/problemnew/show/P2763

////把k个项目向汇点t连容量为ki的容量;
把n个点拆点出来,容量为1(代表用一次)

#include<bits/stdc++.h>
using namespace std;
const int M=5e+5;
const int inf=0x3f3f3f3f;
struct node{
    int v,w,nextt;
}e[M<<1];
int head[M],cur[M],deep[M],s,t,tot;
bool bfs(){
    memset(deep,0,sizeof(deep));
    queue<int>que;
    deep[s]=1;
    que.push(s);
    while(!que.empty()){
        int u=que.front();
        que.pop();
        for(int i=head[u];~i;i=e[i].nextt){
            int v=e[i].v;
            if(deep[v]==0&&e[i].w>0){
                deep[v]=deep[u]+1;
                if(v==t)
                    return true;
                que.push(v);
            }
        }
    }
    return deep[t]==0?false:true;
}
int dfs(int u,int fl){
    if(u==t)
        return fl;
    int ans=0,x=0;
    for(int i=head[u];~i;i=e[i].nextt){
        int v=e[i].v;
        if(deep[v]==deep[u]+1&&e[i].w>0){
            x=dfs(v,min(fl-ans,e[i].w));
            e[i].w-=x;
            e[i^1].w+=x;
            if(e[i].w)
                cur[u]=i;
            ans+=x;
            if(ans==fl)
                return ans;
        }
    }
    if(ans==0)
        deep[u]=0;
    return ans;
}
int dinic(int n){
    int ans=0;
    while(bfs()){
        for(int i=0;i<=n;i++)
            cur[i]=head[i];
        ans+=dfs(s,inf);

    }
    return ans;
}
void init(){
    memset(head,-1,sizeof(head));
    tot=0;

}
void addedge(int u,int v,int w){
    e[tot].v=v;
    e[tot].w=w;
    e[tot].nextt=head[u];
    head[u]=tot++;
    e[tot].v=u;
    e[tot].w=0;
    e[tot].nextt=head[v];
    head[v]=tot++;
}
int main(){
    init();
    int k,n;
    scanf("%d%d",&k,&n);
    s=0,t=2*n+k+1;
    int sum=0;
    for(int i=1;i<=k;i++){
        int x;
        scanf("%d",&x);
        addedge(i,t,x);
        sum+=x;
    }
    for(int i=1;i<=n;i++)
        addedge(s,k+i,1);
    for(int i=1;i<=n;i++){
        int p;
        addedge(k+i,k+i+n,1);
        scanf("%d",&p);
        while(p--){
            int sign;
            scanf("%d",&sign);
            addedge(k+i+n,sign,1);
        }
    }
    if(dinic(t)!=sum)
        return puts("No Solution!"),0;
    for(int i=1;i<=k;i++){
        printf("%d:",i);
        for(int j=head[i];~j;j=e[j].nextt){
            if(e[j].v!=t&&e[j].w==1){
                printf(" %d",e[j].v-k-n);
            }
        }
        putchar(‘\n‘);
    }
    return 0;
}

8、机器人路径规划问题

不会题;

9、方格取数问题

题目链接:https://www.luogu.org/problemnew/show/P2774

方格取数
题目说不能取有边界

那么我们建图的时候就按有边界的取建图;
我们可以这样理解,我们要去掉一些格子,让整个图按要求联通,达到最大;
把每个方格拆点,边权为方格的值,最大对应全部-最小,最小什么呢?即最小割;

#include<bits/stdc++.h>
using namespace std;
inline int read(){
    int sum=0,x=1;
    char ch=getchar();
    while(ch<‘0‘||ch>‘9‘){
        if(ch==‘-‘)
            x=0;
        ch=getchar();
    }
    while(ch>=‘0‘&&ch<=‘9‘){
        sum=(sum<<1)+(sum<<3)+(ch^48),ch=getchar();
    }
    return x?sum:-sum;
}
inline void write(int x){
    if(x<0)
        putchar(‘-‘),x=-x;
    if(x>9)
        write(x/10);
    putchar(x%10+‘0‘);
}
const int M=2e4+4;
const int inf=0x3f3f3f3f;
struct node{
    int v,nextt,w;
}e[200005];
int head[M],deep[M],cur[M];
int tot,s,t;
int gx[4]={1,-1,0,0};
int gy[4]={0,0,-1,1};
int a[102][102];
void init(){
    memset(head,-1,sizeof(head));
    tot=0;
}
void addedge(int u,int v,int w){
    e[tot].v=v;
    e[tot].w=w;
    e[tot].nextt=head[u];
    head[u]=tot++;
    e[tot].v=u;
    e[tot].w=0;
    e[tot].nextt=head[v];
    head[v]=tot++;
}
bool bfs(){
    memset(deep,0,sizeof(deep));
    deep[s]=1;
    queue<int>que;
    que.push(s);
    while(!que.empty()){
        int u=que.front();
        que.pop();
        for(int i=head[u];~i;i=e[i].nextt){
            int v=e[i].v;
            if(e[i].w>0&&deep[v]==0){
                deep[v]=deep[u]+1;
                if(v==t)
                    return true;
                que.push(v);
            }
        }
    }
    return deep[t]==0?false:true;
}
int dfs(int u,int fl){
    if(u==t)
        return fl;
    int ans=0,x=0;
    for(int i=cur[u];~i;i=e[i].nextt){
        int v=e[i].v;
        if(e[i].w>0&&deep[v]==deep[u]+1){
            x=dfs(v,min(fl-ans,e[i].w));
            e[i].w-=x;
            e[i^1].w+=x;
            if(e[i].w)
                cur[u]=i;
            ans+=x;
            if(ans==fl)
                return ans;
        }
    }
    if(ans==0)
        deep[u]=0;
    return ans;
}
int dinic(int n){
    int ans=0;
    while(bfs()){
        //cout<<"!!"<<endl;
        for(int i=0;i<=n;i++)
            cur[i]=head[i];
        ans+=dfs(s,inf);
    }
    return ans;
}
int main(){
    init();
    int n=read(),m=read();
    //cout<<n<<"~~~~~"<<m<<endl;
    s=0,t=n*m+1;
    int ans=0;
    for(int i=1;i<=n;i++)
        for(int j=1;j<=m;j++)
            a[i][j]=read(),ans+=a[i][j];
    for(int i=1;i<=n;i++){
        for(int j=1;j<=m;j++){
            if((i+j)&1)
                addedge((i-1)*m+j,t,a[i][j]);
            else
                addedge(s,(i-1)*m+j,a[i][j]);
        }
    }
    int sign=1;
    for(int i=1;i<=n;i++){
        for(int j=1;j<=m;j++){
            if(!((i+j)&1)){
                //cout<<"#####"<<sign++<<"########"<<endl;
                for(int k=0;k<4;k++){
                    int tx=i+gx[k];
                    int ty=j+gy[k];
                    if(tx>=1&&tx<=n&&ty>=1&&ty<=m){
                        addedge((i-1)*m+j,(i-1)*m+j+(tx-i)*m+(ty-j),inf);
                        //cout<<(i-1)*m+j+(tx-i)*m+(ty-j)<<endl;
                    }
                }
            }

        }
    }
    write(ans-dinic(t));
    return 0;
}

原文地址:https://www.cnblogs.com/starve/p/10891619.html

时间: 2024-10-07 12:55:17

网络流24题!!!!的相关文章

【网络流24题----14】孤岛营救问题

孤岛营救问题 Time Limit: 1 Sec  Memory Limit: 128 MB Description 1944年,特种兵麦克接到国防部的命令.要求马上赶赴太平洋上的一个孤岛,营救被敌军俘虏的大兵瑞恩.瑞恩被关押在一个迷宫里,迷宫地形复杂,但幸好麦克得到了迷宫的地形图.迷宫的外形是一个长方形,其南北方向被划分为 N行,东西方向被划分为 M列,于是整个迷宫被划分为 N×M个单元.每个单元的位置可用一个有序数对 (单元的行号,单元的列号)来表示.南北或东西方向相邻的 2个单元之间可能互

【网络流24题】

网络流 网络流24题 [最小路径覆盖问题] 关于输出路径,因为即使有反向弧经过左侧点也一定会改变左侧点的去向,若没连向右侧就会被更新到0,所以不用在意. mark记录有入度的右侧点,然后从没入度的右侧点开始把整条路径输出来即可. #include<cstdio> #include<algorithm> #include<cstring> using namespace std; const int maxn=100000,inf=0x3f3f3f3f; int n,m,

【网络流24题】魔术球问题

P1226 - [网络流24题]魔术球问题 Description 假设有n根柱子,现要按下述规则在这n根柱子中依次放入编号为 1,2,3,4......的球. (1)每次只能在某根柱子的最上面放球. (2)在同一根柱子中,任何2个相邻球的编号之和为完全平方数. 试设计一个算法,计算出在n根柱子上最多能放多少个球.例如,在4 根柱子上最多可 放11个球. ′编程任务: 对于给定的n,计算在 n根柱子上最多能放多少个球. Input 第1 行有 1个正整数n,表示柱子数. Output 第一行是球

AC日记——[网络流24题]骑士共存 cogs 746

746. [网络流24题] 骑士共存 ★★☆   输入文件:knight.in   输出文件:knight.out   简单对比时间限制:1 s   内存限制:128 MB 骑士共存问题 «问题描述: 在一个n*n个方格的国际象棋棋盘上,马(骑士)可以攻击的棋盘方格如图所示.棋盘 上某些方格设置了障碍,骑士不得进入. «编程任务: 对于给定的n*n个方格的国际象棋棋盘和障碍标志,计算棋盘上最多可以放置多少个骑 士,使得它们彼此互不攻击. «数据输入: 由文件knight.in给出输入数据.第一行

网络流24题

刷刷基础题来巩固一下基础.. #1.飞行员配对方案问题 pdf链接 听说各大OJ的题面都和pdf不同.. 嗯连边匹配就行.. #include <cstdio> #include <cstring> #include <cstdlib> #include <algorithm> #include <queue> using namespace std; const int Maxn = 110; struct node { int y, next

739. [网络流24题] 运输问题

739. [网络流24题] 运输问题 ★★   输入文件:tran.in   输出文件:tran.out   简单对比时间限制:1 s   内存限制:128 MB «问题描述:«编程任务:对于给定的m 个仓库和n 个零售商店间运送货物的费用,计算最优运输方案和最差运输方案.«数据输入:«结果输出:程序运行结束时,将计算出的最少运输费用和最多运输费用输出到文件tran.out中.输入文件示例 输出文件示例tran.in2 3220 280170 120 21077 39 105 150 186 1

【网络流24题】 No.12 软件补丁问题(最小转移代价 最短路)

[题意] T 公司发现其研制的一个软件中有 n 个错误, 随即为该软件发放了一批共 m 个补丁程序. 每一个补丁程序都有其特定的适用环境, 某个补丁只有在软件中包含某些错误而同时又不包含另一些错误时才可以使用.一个补丁在排除某些错误的同时, 往往会加入另一些错误.换句话说, 对于每一个补丁 i, 都有 2 个与之相应的错误集合 B1[i]和 B2[i],使得仅当软件包含 B1[i]中的所有错误, 而不包含 B2[i]中的任何错误时, 才可以使用补丁 i. 补丁 i 将修复软件中的某些错误 F1[

BZOJ_1221_ [HNOI2001]_软件开发(网络流24题,最小费用流)

描述 http://www.lydsy.com/JudgeOnline/problem.php?id=1221 n天,每天需要r个毛巾,用完以后可以洗,要么花fa洗a天,要么花fb洗b天,毛巾不够了可以话f买一个,问最少需要多少钱. 分析 把每天拆成两个点:x[i]表示第i天的脏毛巾,y[i]表示第i天要用的毛巾. 1.s向x[i]连弧,容量为r[i],花费为0,表示每天会用脏r[i]条毛巾. 2.x[i]向x[i+1]连弧(注意边界),容量为INF,花费为0,表示把第i天的脏毛巾搁置到第i+1

【线性规划与网络流 24题】完成度(1/24)

PS:SDOI2016 Round1滚粗后蒟蒻开始做网络流来自我拯救(2016-04-11再过几天就要考先修课,现在做网络流24题貌似没什么用←退役节奏) 做的题目将附上日期,见证我龟速刷题. 1.飞行员配对方案问题 2016-04-11 二分图最大匹配问题,更新了一下$Dinic$模板,带上了当前弧优化和多路增广.这道题输出方案有很多种,可是没有special judge,所以没有A,但方案数是对的.合法的输出方案只能用匈牙利算法解决. #include<queue> #include<

题解:线性规划与网络流24题 T2 太空飞行计划问题

太空飞行计划问题 问题描述 W教授正在为国家航天中心计划一系列的太空飞行.每次太空飞行可进行一系列商业性实验而获取利润.现已确定了一个可供选择的实验集合E={E1,E2,-,Em},和进行这些实验需要使用的全部仪器的集合I={I1,I2,-In}.实验Ej 需要用到的仪器是I的子集Rj ∈ I.配置仪器Ik的费用为ck美元.实验Ej 的赞助商已同意为该实验结果支付pj 美元.W教授的任务是找出一个有效算法,确定在一次太空飞行中要进行哪些实验并因此而配置哪些仪器才能使太空飞行的净收益最大.这里净收