• [HNOI2006]超级英雄(二分+网络流)


    [HNOI2006]超级英雄

    题目描述

    现在电视台有一种节目叫做超级英雄,大概的流程就是每位选手到台上回答主持人的几个问题,然后根据回答问题的多少获得不同数目的奖品或奖金。主持人问题准备了若干道题目,只有当选手正确回答一道题后,才能进入下一题,否则就被淘汰。为了增加节目的趣味性并适当降低难度,主持人总提供给选手几个“锦囊妙计”,比如求助现场观众,或者去掉若干个错误答案(选择题)等等。

    这里,我们把规则稍微改变一下。假设主持人总共有m道题,选手有n种不同的“锦囊妙计”。主持人规定,每道题都可以从两种“锦囊妙计”中选择一种,而每种“锦囊妙计”只能用一次。我们又假设一道题使用了它允许的锦囊妙计后,就一定能正确回答,顺利进入下一题。现在我来到了节目现场,可是我实在是太笨了,以至于一道题也不会做,每道题只好借助使用“锦囊妙计”来通过。如果我事先就知道了每道题能够使用哪两种“锦囊妙计”,那么你能告诉我怎样选择才能通过最多的题数吗?

    输入输出格式

    输入格式:

    输入的第一行是两个正整数 (n)(m) ( (0 < n < 1001, 0 < m < 1001) )表示总共有 (n) 种“锦囊妙计”,编号为 (0 sim n-1) ,总共有 (m) 个问题。

    以下的 (m) 行,每行两个数,分别表示第 (m) 个问题可以使用的“锦囊妙计”的编号。

    注意,每种编号的“锦囊妙计”只能使用一次,同一个问题的两个“锦囊妙计”可能一样。

    输出格式:

    输出的第一行为最多能通过的题数 (p) ,接下来 (p) 行,每行为一个整数,第 (i) 行表示第 (i) 题使用的“锦囊妙计的编号”。

    如果有多种答案,那么任意输出一种,本题使用 Special Judge 评判答案。

    输入输出样例

    输入样例#1: 复制

    5 6
    3 2
    2 0
    0 3
    0 4
    3 2
    3 2

    输出样例#1: 复制

    4
    3
    2
    0
    4


    题解

    第一眼看到题目。
    这不是一个裸的二分图匹配吗?
    虽然我不会打二分图。。。但是我还是会点网络流的。。
    打一发交上去。
    全WA????
    再看题,原来没有这一次的通关下一次就无法在匹配了。也就是说我们要按顺序匹配过来,如果当前位无法通关,那就不能继续了。那么,这不是裸二分+二分图最大匹配吗?
    打一发。又GG了。40分??
    去bzoj上交,不要输出方案。A了??
    回来检查,发现是输出方案打错了。。。
    友善提醒:不要二分出来以后(二分途中没记录)直接输出方案。要一边二分一边记录啊啊啊啊。


    代码

    #include<cstdio>
    #include<cstring>
    #include<cmath>
    #include<iostream>
    #include<algorithm>
    #include<queue>
    using namespace std;
    const int N=100001;
    const int inf=99999999;
    int n,m,s,t,ans;
    int num=1,head[N],H[N],xx[N],yy[N],line[N],cnt;
    int dep[N];
    struct node{
        int c,next,to;
    }e[N<<1];
    int read(){
        int x=0,w=1;char ch=getchar();
        while(ch>'9'||ch<'0'){if(ch=='-')w=-1;ch=getchar();}
        while(ch>='0'&&ch<='9')x=x*10+ch-'0',ch=getchar();
        return x*w;
    }
    
    void add(int from,int to,int c){
        num++;
        e[num].to=to;
        e[num].c=c;
        e[num].next=head[from];
        head[from]=num;
    }
    
    bool bfs(){
        memset(dep,0,sizeof(dep));
        queue<int>q;q.push(s);dep[s]=1;
        while(!q.empty()){
            int u=q.front();q.pop();
            for(int i=head[u];i;i=e[i].next){
                int v=e[i].to;
                if(!dep[v]&&e[i].c){
                    dep[v]=dep[u]+1;q.push(v);
                }
            }
        }
        return dep[t];
    }
    
    int dfs(int x,int cap){
        if(x==t)return cap;
        for(int& i=H[x];i;i=e[i].next){
            int v=e[i].to;
            if(dep[v]==dep[x]+1&&e[i].c){
                int tmp=dfs(v,min(cap,e[i].c));
                if(tmp){
                    e[i].c-=tmp;e[i^1].c+=tmp;
                    return tmp;
                }
            }
        }
        return 0;
    }
    
    int dinic(){
        int ans=0;
        while(bfs()){
            for(int i=s;i<=t;i++)H[i]=head[i];
            while(int f=dfs(s,inf))ans+=f;
        }
        return ans;
    }
    
    void solve(int mid){
        cnt=0;
        for(int i=1;i<=mid;i++){
            for(int j=head[i];j;j=e[j].next){
                int v=e[j].to;
                if(!e[j].c&&v!=s){
                    line[++cnt]=v-1-mid;
                    continue;
                }
            }
        }
    }
    
    bool judge(int mid){
        memset(head,0,sizeof(head));
        memset(H,0,sizeof(H));
        memset(e,0,sizeof(e));
        for(int i=1;i<=mid;i++){
        add(i,xx[i]+mid,1);add(xx[i]+mid,i,0);
        add(i,yy[i]+mid,1);add(yy[i]+mid,i,0);
        }
        for(int i=1;i<=n;i++)add(i+mid,t,1),add(t,i+mid,0);
        for(int i=1;i<=mid;i++)add(s,i,1),add(i,s,0);
        if(dinic()==mid){solve(mid);return true;}
        else return false;
    }
    
    
    int main()
    {
        n=read();m=read();s=0;t=n+m+1;
        for(int i=1;i<=m;i++){
            xx[i]=read()+1;yy[i]=read()+1;
        }
        int l=0,r=m;
        while(r>l){
            int mid=(l+r+1)>>1;
            if(judge(mid))l=mid;
            else r=mid-1;
        }
        printf("%d
    ",l);
        for(int i=1;i<=cnt;i++)cout<<line[i]<<endl;
        return 0;
    }
    
  • 相关阅读:
    C#制作windows屏保实战
    创建一个可以修改不可以删除的文件夹或文件,windows目录和文件权限实测总结
    分享一下我用C#写的贪吃蛇和迷宫
    用C#做的汉诺塔游戏以及对汉诺塔递归的简单理解
    纪念一下即将逝去的flash,曾今的flash入门学习示例《别盯着我》C#版
    C#中关于变量的作用域不易理解的特例
    列出文件夹和遍历文件夹的区别
    怎样创建无法直接删除的文件夹--关于windows权限的迷思
    用C#写的后台整点报时工具
    用C#写差异文件备份工具
  • 原文地址:https://www.cnblogs.com/hhh1109/p/9535267.html
Copyright © 2020-2023  润新知