zoukankan      html  css  js  c++  java
  • POJ3041:Asteroids——题解

    http://poj.org/problem?id=3041

    题目大意:激光可以干掉一整行或一整列陨石,求最少激光次数。

    ——————————————————

    二分图匹配,对于每一个陨石将它的横纵坐标相连。

    然后发现我们需要将每一条边中的端点之一都覆盖掉,就是最小点覆盖。

    有结论最小点覆盖=最大匹配数。

    然后本题就切了。

    #include <cstdio>
    #include <iostream>
    #include <cmath>
    #include <cstring>
    #include <algorithm>
    using namespace std;
    const int M=10010;
    const int N=1010;
    const int INF=2147483640;
    inline int read(){
        int X=0,w=0;char ch=0;
        while(ch<'0'||ch>'9'){w|=ch=='-';ch=getchar();}
        while(ch>='0'&&ch<='9')X=(X<<3)+(X<<1)+(ch^48),ch=getchar();
        return w?-X:X;
    }
    struct node{
        int next;
        int to;
        int w;
    }edge[N*2+M*2];
    int head[N],cnt=-1;
    void add(int u,int v,int w){//u起点v终点w容量 
        cnt++;
        edge[cnt].to=v;
        edge[cnt].w=w;
        edge[cnt].next=head[u];
        head[u]=cnt;
        return;
    }
    int lev[N],cur[N];//lev层数,cur[i]为以i为起点的边的编号 
    bool bfs(int m){//强制1为源点,m为汇点 
        int dui[m],r=0;//队列和右指针 
        for(int i=1;i<=m;i++){//初始化 
            lev[i]=-1;
            cur[i]=head[i];
        }
        dui[0]=1,lev[1]=0;
        int u,v;//u起点v终点 
        for(int l=0;l<=r;l++){//左指针 
            u=dui[l];
            for(int e=head[u];e!=-1;e=edge[e].next){
                v=edge[e].to;
                if(edge[e].w>0&&lev[v]==-1){//1.能走 2.未分层 
                    lev[v]=lev[u]+1;
                    r++;
                    dui[r]=v;//v入队 
                    if(v==m)return 1;//分层完毕 
                }
            }
        }
        return 0;//无法分层 
    }
    int dinic(int u,int flow,int m){//u当前点,flow为下面的点能够分配多大的流量,m终点 
        if(u==m)return flow;//终点直接全流入
        int res=0,delta;//res实际流量 
        for(int &e=cur[u];e!=-1;e=edge[e].next){//'&'相当于cur[u]=e;即流满的边不会再被扫一次 
            int v=edge[e].to;
            if(edge[e].w>0&&lev[u]<lev[v]){//只能从低层往高层流 
                delta=dinic(v,min(edge[e].w,flow-res),m); 
                if(delta>0){//如果增广 
                    edge[e].w-=delta;//正向边容量减少 
                    edge[e^1].w+=delta;//反向边仍量增加(暗示退流) 
                    res+=delta;//扩张流量增加 
                    if(res==flow)break;//可流的都流完了,及时跳出 
                }
            }
        }
        if(res!=flow)lev[u]=-1;//没流完,说明以后不能从这个点流出任何流量,那就不需要这个点了 
        return res;
    }
    int main(){
        int n=read();
        int k=read();
        int m=n*2+2;
        memset(head,-1,sizeof(head));
        for(int i=1;i<=k;i++){
        int s=read()+1;
        int e=read()+n+1;
        add(s,e,1);
        add(e,s,0);
        }
        for(int i=1;i<=n;i++){
        add(1,i+1,1);
        add(i+1,1,0);
        add(i+n+1,m,1);
        add(m,i+n+1,0);
        }
        int ans=0;
        while(bfs(m)==1)ans+=dinic(1,INF,m);
        printf("%d
    ",ans);
        return 0;
    }
  • 相关阅读:
    FZU.Software Engineering1816 ·The Second Assignment of the Team
    18软工实践-第五次作业-结对作业2
    福大软工1816 · 第四次作业
    软件工程实践第三次作业——结对作业(一)
    软工第二次作业——个人项目
    福大软工1816 · 团队现场编程实战(抽奖系统)
    Alpha 冲刺 (3/10)
    Alpha 冲刺 (2/10)
    Alpha 冲刺 (1/10)
    福大软工 · 第七次作业
  • 原文地址:https://www.cnblogs.com/luyouqi233/p/7930680.html
Copyright © 2011-2022 走看看