小行星群
时间限制: 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; }