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\n",ans);
    return 0;
}

 

posted @ 2017-11-30 19:28  luyouqi233  阅读(333)  评论(0编辑  收藏  举报