小行星群 网络流 二分图

小行星群

时间限制: 1 Sec  内存限制: 128 MB

题目描述

贝西驾驶着宇宙飞船,准备穿过危险的小行星群。它所在的星域可以分为 N × N 个网格,小行
星存在于其中的 M 个网格。贝西要安全通过这片星域,必须消灭所有的小行星。好在她有一件终极
兵器——地图炮。只要一发炮弹就可以清除同一行或同一列网格里的所有小行星。这种弹药很贵,所
以贝西希望尽量少来几发。给出所有的小行星的位置,请算出最少需要几发炮弹才能消灭它们。

输入

• 第一行:两个整数 N 和 M,1 ≤ N ≤ 500, 1 ≤ M ≤ 10 4
• 第二行到第 M + 1 行:第 i + 1 行有两个整数 R i 和 C i ,1 ≤ R i ,C i ≤ N

输出

• 单个整数:表示最少需要发射的多少炮弹

样例输入

3 4 1 1 1 3 2 2 3 2

样例输出

2

提示

向第一行开炮,消灭 (1,1) 和 (1,3),再向第

二列开炮,消灭 (2,2) 和 (3,2)
题解:
此题可以用网络流最大流解决,
1.源点和每一行连接,汇点和每一列连接,残量为1。
2.根据输入的情况将行和列连一条残量为1的边。
3.然后就是最大流了。
当然二分图对于这道题来说效率更高,这里只提供最大流代码。
#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<cstdlib>
#include<algorithm>
#include<queue>
#include<stack>
#include<ctime>
#include<vector>
using namespace std;
int n,m;
struct node
{
    int next,to,cap;
}edge[600001];
int head[2001],size=1;
void putin(int from,int to,int cap)
{
    size++;
    edge[size].to=to;
    edge[size].cap=cap;
    edge[size].next=head[from];
    head[from]=size;
}
void in(int from,int to,int cap)
{
    putin(from,to,cap);
    putin(to,from,0);
}
int dist[2001],numbs[2001];
void bfs(int src,int des)
{
    int i,j;
    queue<int>mem;
    for(i=0;i<=n*2+1;i++){dist[i]=n*2+2;numbs[i]=0;}
    mem.push(des);
    dist[des]=0;numbs[0]=1;
    while(!mem.empty())
    {
        int x=mem.front();mem.pop();
        for(i=head[x];i!=-1;i=edge[i].next)
        {
            int y=edge[i].to;
            if(dist[y]==n*2+2&&edge[i].cap==0)
            {
                dist[y]=dist[x]+1;
                numbs[dist[y]]++;
                mem.push(y);
            }
        }
    }
    return;
}
int dfs(int src,int flow,int des)
{
    if(src==des)return flow;
    int low=0,i,mindist=n*2+2;
    for(i=head[src];i!=-1;i=edge[i].next)
    {
        int y=edge[i].to;
        if(edge[i].cap)
        {
            if(dist[y]==dist[src]-1)
            {
                int t=dfs(y,min(flow-low,edge[i].cap),des);
                edge[i].cap-=t;
                edge[i^1].cap+=t;
                low+=t;
                if(dist[0]==n*2+2)return low;
                if(flow==low)break;
            }
            mindist=min(mindist,dist[y]+1);
        }
    }
    if(!low)
    {
        if(!(--numbs[dist[src]]))dist[0]=n*2+2;
        ++numbs[dist[src]=mindist];
    }
    return low;
}
int ISAP(int src,int des)
{
    int ans=0;
    bfs(src,des);
    while(dist[src]<n*2+2)ans+=dfs(src,2e8,des);
    return ans;
}
int main()
{
    int i,j;
    scanf("%d%d",&n,&m);
    memset(head,-1,sizeof(head));
    for(i=1;i<=n;i++)in(0,i,1);
    for(i=n+1;i<=n*2;i++)in(i,n*2+1,1);
    for(i=1;i<=m;i++)
    {
        int from,to;
        scanf("%d%d",&from,&to);
        in(from,to+n,1);
    }
    int maxflow=ISAP(0,2*n+1);
    cout<<maxflow;
    return 0;
}

 

posted @ 2017-05-25 17:36  kakakakakaka  阅读(258)  评论(0编辑  收藏  举报

Never forget why you start

//鼠标爆炸特效