这道题目的正统解法应该是匹配。
但是同样也可以用上下界网络流来解决。
每一行至少要射中一个,那么下界是1上界INF。
每一列只能射中一个,那么上下界都是1,。
对于每一个白色格子,无下界,上界是1.
将每一列与源点相连,容量INF。
将每一行与汇点相连,容量0
更具白点位置连列和行,容量为1
在更具这个网络求一次可行流。
Shooting Contest
Time Limit: 1000MS | Memory Limit: 10000K | |||
Total Submissions: 3345 | Accepted: 1213 | Special Judge |
Description
Welcome to the Annual Byteland Shooting Contest. Each competitor will shoot to a target which is a rectangular grid. The target consists of r*c squares located in r rows and c columns. The squares are coloured white or black. There are exactly two white squares and r-2 black squares in each column. Rows are consecutively labelled 1,..,r from top to bottom and columns are labelled 1,..,c from left to right. The shooter has c shots.
A volley of c shots is correct if exactly one white square is hit in each column and there is no row without white square being hit. Help the shooter to find a correct volley of hits if such a volley exists.
Example
Consider the following target:
Volley of hits at white squares in rows 2, 3, 1, 4 in consecutive columns 1, 2, 3, 4 is correct.
Write a program that: verifies whether any correct volley of hits exists and if so, finds one of them.
A volley of c shots is correct if exactly one white square is hit in each column and there is no row without white square being hit. Help the shooter to find a correct volley of hits if such a volley exists.
Example
Consider the following target:
Volley of hits at white squares in rows 2, 3, 1, 4 in consecutive columns 1, 2, 3, 4 is correct.
Write a program that: verifies whether any correct volley of hits exists and if so, finds one of them.
Input
The first line of the input contains the number of data blocks x, 1 <= x <= 5. The following lines constitute x blocks. The first block starts in the second line of the input file; each next block starts directly after the previous one.
The first line of each block contains two integers r and c separated by a single space, 2 <= r <= c <= 1000. These are the numbers of rows and columns, respectively. Each of the next c lines in the block contains two integers separated by a single space. The integers in the input line i + 1 in the block, 1 <= i <= c, are labels of rows with white squares in the i-th column.
The first line of each block contains two integers r and c separated by a single space, 2 <= r <= c <= 1000. These are the numbers of rows and columns, respectively. Each of the next c lines in the block contains two integers separated by a single space. The integers in the input line i + 1 in the block, 1 <= i <= c, are labels of rows with white squares in the i-th column.
Output
For the i-th block, 1 <= i <= x, your program should write to the i-th line of the standard output either a sequence of c row labels (separated by single spaces) forming a correct volley of hits at white squares in consecutive columns 1, 2, ..., c, or one word NO if such a volley does not exists.
Sample Input
2 4 4 2 4 3 4 1 3 1 4 5 5 1 5 2 4 3 4 2 4 2 3
Sample Output
2 3 1 4 NO#include<iostream> #include<cstdio> using namespace std; #define MAXN 20010 #define MAXM 500010 #define INF 0xFFFFFF struct edge { int to,c,next; }; edge e[MAXM]; int head[MAXN], en,vn; int r,c,n,m; int dis[MAXN]; int gap[MAXN]; int st, ed; int in[MAXN]; int l[MAXM]; void add(int a, int b, int c) { e[en].to=b; e[en].c=c; e[en].next=head[a]; head[a]=en++; e[en].to=a; e[en].c=0; e[en].next=head[b]; head[b]=en++; } int isap(int u,int flow) { if(u==ed) return flow; int j,mindis=vn-1,t=flow,d; for(j=head[u];j!=-1;j=e[j].next) { int v=e[j].to,val=e[j].c; if(val>0) { if(dis[v]+1==dis[u]) { if(t<e[j].c) d=t; else d=e[j].c; d=isap(v,d); e[j].c-=d,e[j^1].c+=d; t-=d; if(dis[st]>=vn) return flow-t; if(t==0) break; } if(dis[v]<mindis) mindis=dis[v]; } } if(t==flow) { --gap[dis[u]]; if (gap[dis[u]]==0) dis[st]=vn; dis[u]=mindis+1; ++gap[dis[u]]; } return flow-t; } int maxflow() { int ret=0; memset(gap,0,sizeof(gap)); memset(dis,0,sizeof(dis)); gap[0] = vn; while (dis[st]<vn) ret+=isap(st, INF); return ret; } int limitflow() { int i,st0,ed0,en0,ret=0; st0=st,ed0=ed,en0=en; st=vn++,ed=vn++; head[st]=head[ed]=-1; for(i=0;i<vn-2;++i) { if(in[i]>0) add(st,i,in[i]); if(in[i]<0) add(i,ed,-in[i]); } add(ed0,st0,INF); add(st0,ed0,INF); maxflow(); for(i=head[st];i!=-1;i=e[i].next) if(e[i].c) return -1; return 1; } void solve() { int a,b; scanf("%d%d",&r,&c); vn=r+c+2,en=0,st=0,ed=r+c+1; memset(head,-1,sizeof(head)); memset(in,0,sizeof(in)); for(int i=1;i<=c;i++) { scanf("%d%d",&a,&b); add(i,a+c,1); add(i,b+c,1); } for(int i=1;i<=c;i++) { add(st,i,0); //列上限1,下限1 in[st]--; in[i]++; } for(int i=1;i<=r;i++) { add(i+c,ed,INF); //下限1,无上限 in[i+c]--; in[ed]++; } if(limitflow()==-1) { printf("NO\n"); return ; } int counts=0; for(int i=0;i<c*2;i++) { if(e[(i*2)^1].c) { counts++; printf("%d",e[i*2].to-c); if(counts!=c) printf(" "); } } printf("\n"); } int main() { int t; scanf("%d",&t); while(t--) solve(); return 0; }