文文殿下网络流24题计划

Posted syameimaru

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了文文殿下网络流24题计划相关的知识,希望对你有一定的参考价值。

飞行员配对方案问题

题目背景

第二次世界大战时期..

题目描述

英国皇家空军从沦陷国征募了大量外籍飞行员。由皇家空军派出的每一架飞机都需要配备在航行技能和语言上能互相配合的2 名飞行员,其中1 名是英国飞行员,另1名是外籍飞行员。在众多的飞行员中,每一名外籍飞行员都可以与其他若干名英国飞行员很好地配合。如何选择配对飞行的飞行员才能使一次派出最多的飞机。对于给定的外籍飞行员与英国飞行员的配合情况,试设计一个算法找出最佳飞行员配对方案,使皇家空军一次能派出最多的飞机。

对于给定的外籍飞行员与英国飞行员的配合情况,编程找出一个最佳飞行员配对方案,使皇家空军一次能派出最多的飞机。

输入输出格式

输入格式:

第 1 行有 2 个正整数 m 和 n。n 是皇家空军的飞行员总数(n<100);m 是外籍飞行员数(m<=n)。外籍飞行员编号为 1~m;英国飞行员编号为 m+1~n。

接下来每行有 2 个正整数 i 和 j,表示外籍飞行员 i 可以和英国飞行员 j 配合。最后以 2个-1 结束。

输出格式:

第 1 行是最佳飞行员配对方案一次能派出的最多的飞机数 M。接下来 M 行是最佳飞行员配对方案。每行有 2个正整数 i 和 j,表示在最佳飞行员配对方案中,飞行员 i 和飞行员 j 配对。如果所求的最佳飞行员配对方案不存在,则输出‘No Solution!’。

题解:

本质上是二分图最大匹配,直接建图就好。

#include <cstdio>
#include <cstring>
#include <queue>
#include <vector>

const int maxn=5000;
namespace Dinic {
    struct Edge{
        int u,v,cap,flow;
        Edge(int u,int v,int cap,int flow):u(u),v(v),cap(cap),flow(flow){
        }
    };
    std::vector<Edge> edges;
    std::vector<int> G[maxn];
    int n,s,t;
    int d[maxn];
    bool vis[maxn];
    int cur[maxn];
    void addEdge(int u,int v,int cap) {
        edges.push_back(Edge(u,v,cap,0));
        edges.push_back(Edge(v,u,0,0));
        int m=edges.size();
        G[u].push_back(m-2);
        G[v].push_back(m-1);
    }
    bool BFS() {
        std::queue<int> Q;
        memset(vis,0,sizeof(vis));
        memset(d,0,sizeof(d));
        Q.push(s);
        d[s]=0;
        vis[s]=1;
        while(!Q.empty()) {
            int u=Q.front();
            Q.pop();
            for(register int i=0;i<G[u].size();++i) {
                Edge& e=edges[G[u][i]];
                if(!vis[e.v]&&e.cap>e.flow) {
                    d[e.v]=d[u]+1;
                    Q.push(e.v);
                    vis[e.v]=1;
                }
            }
        }
        return vis[t];
    }
    
    int DFS(int u,int a) {
        if(u==t||a==0) return a;
        int flow=0,f;
        for(register int &i=cur[u];i<G[u].size();++i) {
            Edge& e=edges[G[u][i]];
            if(d[e.v]==d[u]+1&&(f=DFS(e.v,std::min(a,e.cap-e.flow)))>0) {
                e.flow+=f;
                a-=f;
                edges[G[u][i]^1].flow-=f;
                flow+=f;
                if(a==0) break;
            }   
        }
        return flow;
    }
    int maxFlow(int s,int t) {
        Dinic::s=s;
        Dinic::t=t;
        int ans=0;
        while(BFS()) {
            memset(cur,0,sizeof(cur));
            ans+=DFS(s,t);
        }
        return ans;
    }
}

int n,m,a,b;
int main() {
//  freopen("test.txt","r",stdin);
    scanf("%d%d",&m,&n);
    scanf("%d%d",&a,&b);
    while(a!=-1&&b!=-1) {
        Dinic::addEdge(a,b,1);
        scanf("%d%d",&a,&b);
    }
    for(register int i=1;i<=m;i++) {
        Dinic::addEdge(0,i,1);
    }
    for(register int i=1;i<=n;i++) {
        Dinic::addEdge(i+m,n+m+1,1);
    }
    int mx=Dinic::maxFlow(0,n+m+1);
    if(mx==0) {
        puts("No Solution!");
        return 0;
    }
    printf("%d
",mx);
    for(register int i=1;i<=m;i++) {
        for(register int j=0;j<Dinic::G[i].size();++j) {
            Dinic::Edge& e = Dinic::edges[Dinic::G[i][j]];
            if(e.flow==1){
            printf("%d %d
",i,e.v);
            break;
            }
        }
    }
    return 0;
}

软件补丁问题

题目背景

none!

题目描述

T 公司发现其研制的一个软件中有 n 个错误,随即为该软件发放了一批共 m 个补丁程序。每一个补丁程序都有其特定的适用环境,某个补丁只有在软件中包含某些错误而同时又不包含另一些错误时才可以使用。一个补丁在排除某些错误的同时,往往会加入另一些错误。

换句话说,对于每一个补丁 i,都有 2 个与之相应的错误集合 B1[i]和 B2[i],使得仅当软件包含 B1[i]中的所有错误,而不包含 B2[i]中的任何错误时,才可以使用补丁 i。补丁 i 将修复软件中的某些错误 F1[i],而同时加入另一些错误 F2[i]。另外,每个补丁都耗费一定的时间。

试设计一个算法,利用 T 公司提供的 m 个补丁程序将原软件修复成一个没有错误的软件,并使修复后的软件耗时最少。对于给定的 n 个错误和 m 个补丁程序,找到总耗时最少的软件修复方案。

输入输出格式

输入格式:

第 1 行有 2 个正整数 n 和 m,n 表示错误总数,m表示补丁总数,1<=n<=20, 1<=m<=100。

接下来 m 行给出了 m 个补丁的信息。每行包括一个正整数,表示运行补丁程序 i 所需时间,以及 2 个长度为 n 的字符串,中间用一个空格符隔开。

第 1 个字符串中,如果第 k 个字符 bk 为“+”,则表示第 k 个错误属于 B1[i],若为“-”,则表示第 k 个错误属于 B21[i],若为“0”,则第 k 个错误既不属于 B1[i]也不属于 B2[i],即软件中是否包含第 k 个错误并不影响补丁 i 的可用性。

第 2 个字符串中,如果第 k 个字符 bk为“-”,则表示第 k 个错误属于 F1[i],若为“+”,则表示第 k 个错误属于 F2[i],若为“0”,则第 k 个错误既不属于 F1[i]也不属于 F2[i],即软件中是否包含第 k 个错误不会因使用补丁i 而改变。

输出格式:

程序运行结束时,将总耗时数输出。如果问题无解,则输出 0。

题解

没想到网络流做法,可以直接跑最短路。

#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<cmath>
#include<algorithm>
#include<iostream>
#include<string>
#include<ctime>
#define LL long long
using namespace std;
const int N=21,M=101,inf=1e9;
int n,m,val[M],b1[M],b2[M],f1[M],f2[M],dis[1<<N],q[1<<(N+1)],h,t;
bool inq[1<<N];
char s[N];
int read() {int d=0,f=1; char c=getchar(); while (c<'0'||c>'9') {if (c=='-') f=-1; c=getchar();} while (c>='0'&&c<='9') d=(d<<3)+(d<<1)+c-48,c=getchar(); return d*f;}
void init()
{
    n=read(); m=read();
    for (int i=1;i<=m;i++)
    {
        val[i]=read();
        scanf("%s",&s);
        for (int j=0;j<n;j++)
            if (s[j]=='+') b1[i]|=(1<<j);
            else if (s[j]=='-') b2[i]|=(1<<j);
        scanf("%s",&s);
        for (int j=0;j<n;j++)
            if (s[j]=='+') f2[i]|=(1<<j);
            else if (s[j]=='-') f1[i]|=(1<<j);
    }
}
void spfa()
{
    int ljj=(1<<n)-1;
    for (int i=0;i<ljj;i++) dis[i]=inf;
    h=1; t=1;
    q[1]=ljj; dis[ljj]=0;
    while (h<=t)
    {
        int x=q[h++]; inq[x]=0;
        for (int i=1;i<=m;i++)
            if (!(x&b2[i])&&(x|b1[i])==x)
            {
                int y=x&(~f1[i])|f2[i];
                if (dis[x]+val[i]<dis[y])
                {
                    dis[y]=dis[x]+val[i];
                    if (!inq[y]) q[++t]=y,inq[y]=1;
                }
            }
    }
}
int main()
{
    init();
    spfa();
    if (dis[0]==inf) printf("0");
    else printf("%d",dis[0]);
    return 0;
}

以上是关于文文殿下网络流24题计划的主要内容,如果未能解决你的问题,请参考以下文章

文文殿下数论一些经典结论

[文文殿下]并查集详细解读

文文殿下浅析scanf源码

文文殿下[APIO2010]特别行动队 题解

文文殿下扩展中国剩余定理(板子)

文文殿下CF1175F The Number of Subpermutations