n<=500,n*n网格给m<=10000个点,每次发射子弹打掉一行或一列的点,求最少几发子弹。
网络流经典模型,每行每列看成点,一个(x,y)表示,表示第x行的点和表示第y列的点必有一个要选,连边。接下来二分图匹配或最大流即可。
1 #include<cstdio> 2 #include<cstring> 3 #include<algorithm> 4 #include<cstdlib> 5 //#include<iostream> 6 using namespace std; 7 8 int n,m; 9 #define maxn 1011 10 #define maxm 12011*2 11 struct Edge{int from,to,next,cap,flow;}; 12 const int inf=0x7fffffff; 13 struct Network 14 { 15 Edge edge[maxm];int n,s,t,le; 16 int first[maxn],dis[maxn],cur[maxn]; 17 void clear(int n) 18 { 19 memset(first,0,sizeof(first)); 20 le=2;this->n=n; 21 } 22 void add_edge(int x,int y,int v) 23 { 24 Edge &e=edge[le]; 25 e.to=y;e.from=x; 26 e.cap=v;e.flow=0; 27 e.next=first[x]; 28 first[x]=le++; 29 } 30 void insert(int x,int y,int v) 31 { 32 add_edge(x,y,v); 33 add_edge(y,x,0); 34 } 35 int que[maxn],head,tail; 36 bool bfs() 37 { 38 memset(dis,0,sizeof(dis)); 39 dis[s]=1; 40 que[head=(tail=1)-1]=s; 41 while (head!=tail) 42 { 43 const int x=que[head++]; 44 for (int i=first[x];i;i=edge[i].next) 45 { 46 Edge &e=edge[i]; 47 if (e.cap>e.flow && !dis[e.to]) 48 { 49 dis[e.to]=dis[x]+1; 50 que[tail++]=e.to; 51 } 52 } 53 } 54 return dis[t]; 55 } 56 int dfs(int x,int a) 57 { 58 if (x==t || !a) return a; 59 int flow=0,f; 60 for (int &i=cur[x];i;i=edge[i].next) 61 { 62 Edge &e=edge[i]; 63 if (dis[e.to]==dis[x]+1 && (f=dfs(e.to,min(a,e.cap-e.flow)))>0) 64 { 65 flow+=f; 66 a-=f; 67 e.flow+=f; 68 edge[i^1].flow-=f; 69 if (!a) break; 70 } 71 } 72 return flow; 73 } 74 int Dinic(int s,int t) 75 { 76 this->s=s;this->t=t; 77 int ans=0; 78 while (bfs()) 79 { 80 for (int i=1;i<=n;i++) cur[i]=first[i]; 81 ans+=dfs(s,inf); 82 } 83 return ans; 84 } 85 }G; 86 int x,y; 87 int main() 88 { 89 scanf("%d%d",&n,&m); 90 G.clear(n*2+2); 91 int s=n*2+1,t=s+1; 92 for (int i=1;i<=m;i++) 93 { 94 scanf("%d%d",&x,&y); 95 G.insert(x,y+n,1); 96 } 97 for (int i=1;i<=n;i++) G.insert(s,i,1); 98 for (int i=1;i<=n;i++) G.insert(i+n,t,1); 99 printf("%d ",G.Dinic(s,t)); 100 return 0; 101 }