That was a good question. The contest rules state that every problem should be prepared by two persons exactly: one should write a statement, the other one should prepare a set of tests. Generally, professional problemsetters have license for only one of the tasks, but some of them can do both. Besides, to eliminate a possibility of conflicts between the problemsetters working on the same problem, the difference of their ranks should be equal to 2.
input | output |
---|---|
7 Poll anything 8 Tejat statements 6 Mebsuta testdata 6 Propus testdata 4 Alzir anything 7 Mekbuda anything 3 Dirah testdata 9 |
3 Poll Mebsuta Tejat Propus Alzir Dirah |
题目很长,没有全部复制过来,贴了重要的那一段。
题意:有n个人,每个人各自会 statements 或者 testdata ,或者两种都会 anything 。 后面还有一个数字rank。
然后找最大匹配,要求,必须有个人会 statements 有个人会testdata。然后rank的差要正好是2。
做法:因为rank差要2。 如 0 1 |2 3 | 4 5| 6 7,如果两个数两个数直接隔开当作一个格的话,可以发现只有奇数格和偶数格才有可能会匹配。所以可以把rank%4,如果等于0 1,放一侧,如果等于 2,3 放另一侧。然后计算最大匹配。
注意:会statements 的 输出在左,另一个输出在右。
失败的案例:一开始就想到了二分匹配,用最大流来构图做的。当时想的是 把所有人左边放一排,右边放一排,然后把符合要求的连起来,求最大匹配。 因为一直找不到错误案例,所以WA了很多次。
总结:二分匹配,如果给的数据不是对立的两堆,而是一堆的话。要想方法把这一堆分成两堆,两堆各自之中 一定没有可以相互匹配的。
#pragma warning (disable:4786) #include <stdio.h> #include <stdlib.h> #include <string.h> #include <limits.h> #include <malloc.h> #include <ctype.h> #include <math.h> #include <string> #include <iostream> #include <algorithm> using namespace std; #include <stack> #include <queue> #include <vector> #include <deque> #include <set> #include <map> #define N 1200 int visit[N]; int mark[N]; int match[N][N]; int n,m,k; int dfs(int x) { int i; for(i=1;i<=m;i++) { if(!visit[i]&&match[x][i]) { visit[i]=1; if(mark[i]==-1||dfs(mark[i])) { mark[i]=x; return 1; } } } return 0; } int hungary () { memset(mark,-1,sizeof(mark)); int maxx=0,j; for(j=1;j<=n;j++) { memset(visit,0,sizeof(visit)); if(dfs(j)) maxx++; } return maxx; } string name[1010]; int sta[1010],rak[1010]; int zuo[1010],you[1010]; int main() { int maxx,sum; while(scanf("%d",&sum)!=EOF) //k 个配 { for(int i=1;i<=sum;i++) { string status; cin>>name[i]>>status>>rak[i]; if(status=="anything") sta[i]=3; else if(status=="statements") sta[i]=1; else sta[i]=2; } n=m=0; for(int i=1;i<=sum;i++) { if(rak[i]%4<2) zuo[++n]=i; else you[++m]=i; } memset(match,0,sizeof(match)); for(int i=1;i<=n;i++) { for(int j=1;j<=m;j++) { if((sta[zuo[i]]|sta[you[j]])==3&&abs(rak[zuo[i]]-rak[you[j]])==2) match[i][j]=1; } } maxx=hungary(); printf ("%d\n",maxx); for(int i=1;i<=m;i++)//n=mark[m] { if(~mark[i]) { int fir=zuo[mark[i]]; int sec=you[i]; if(sta[fir]==2) swap(fir,sec); if(sta[sec]==1) swap(fir,sec); cout<<name[fir]<<' '<<name[sec]<<endl; } } } return 0; }
构图失败的:
#pragma warning (disable:4786) #include <stdio.h> #include <stdlib.h> #include <string.h> #include <limits.h> #include <malloc.h> #include <ctype.h> #include <math.h> #include <string> #include <iostream> #include <algorithm> using namespace std; #include <stack> #include <queue> #include <vector> #include <deque> #include <set> #include <map> const int MAXN = 22222;//点数的最大值 const int MAXM = 9000000;//边数的最大值 const int INF = 2000000000; struct Edge { int to,next,cap,flow; }edge[MAXM];//注意是MAXM int tol; int head[MAXN]; int gap[MAXN],dep[MAXN],cur[MAXN]; void init() { tol = 0; memset(head,-1,sizeof (head)); } void addedge (int u,int v,int w,int rw = 0)//网络流要有反向弧 { edge[tol].to = v; edge[tol].cap = w; edge[tol].flow = 0; edge[tol].next = head[u]; head[u] = tol++; edge[tol].to = u; edge[tol].cap = rw; edge[tol].flow = 0; edge[tol].next = head[v]; head[v] = tol++; } int Q[MAXN]; void BFS(int start,int end) { memset(dep,-1,sizeof(dep)); memset(gap,0,sizeof(gap)); gap[0] = 1; int front = 0, rear = 0; dep[end] = 0; Q[rear++] = end; while(front != rear) { int u = Q[front++]; for(int i = head[u]; i != -1; i = edge[i].next) { int v = edge[i]. to; if(dep[v] != -1)continue; Q[rear++] = v; dep[v] = dep[u] + 1; gap[dep[v]]++; } } } int S[MAXN]; int sap(int start,int end, int N)//有几个点 { BFS(start,end); memcpy(cur,head,sizeof(head)); int top = 0; int u = start; int ans = 0; int i; while(dep[start] < N) { if(u == end) { int Min = INF; int inser; for( i = 0;i < top;i++) { if(Min > edge[S[i]].cap - edge[S[i]].flow) { Min = edge[S[i]].cap - edge[S[i]].flow; inser = i; } } for( i = 0;i < top;i++) { edge[S[i]]. flow += Min; edge[S[i]^1].flow -= Min; } ans += Min; top = inser; u = edge[S[top]^1].to; continue; } bool flag = false; int v; for( i = cur[u]; i != -1; i = edge[i]. next) { v = edge[i]. to; if(edge[i].cap - edge[i].flow && dep[v]+1 == dep[u]) { flag = true; cur[u] = i; break; } } if(flag) { S[top++] = cur[u]; u = v; continue; } int Min = N; for( i = head[u]; i != -1; i = edge[i].next) { if(edge[i].cap - edge[i].flow && dep[edge[i].to] < Min) { Min = dep[edge[i].to]; cur[u] = i; } } gap[dep[u]]--; if(!gap[dep[u]]) return ans; dep[u] = Min + 1; gap[dep[u]]++; if(u != start)u = edge[S[--top]^1].to; } return ans; } /* int main() { int n,m,a,b,c; while(scanf("%d%d",&n,&m)!=EOF) { init(); for(int i=1;i<=n;i++) { scanf("%d%d%d",&a,&b,&c); addedge(a,b,c,0); } printf("%d\n",sap(1,m,m)); } return 0; }*/ int sta[1010]; string name[1010]; int rak[1010]; int main() { int n; while(scanf("%d",&n)!=EOF) // 0-2n-1 是点 左边i*2 右边2*i+1 ss=2*n ee=2*n+1 { init(); int ss=2*n,ee=2*n+1; for(int i=0;i<n;i++) { string status; cin>>name[i]>>status>>rak[i]; if(status=="anything") sta[i]=3; else if(status=="statements") sta[i]=1; else sta[i]=2; addedge(ss,i*2,1,0); addedge(i*2+1,ee,1,0);//2*n条边 } for(int i=0;i<n;i++) { for(int j=0;j<i;j++) { if((sta[i]|sta[j])==3&&abs(rak[i]-rak[j])==2) { addedge(j*2,i*2+1,1,0); addedge(i*2,j*2+1,1,0); //printf("%d %d\n",i,j); } } } int ans=sap(ss,ee,2*n+2); printf("%d\n",ans/2); for(int i=4*n;i<tol;i+=4) { if(edge[i].flow==1) { int fir=edge[i+1].to/2; int sec=edge[i].to/2; if(sta[fir]==2) swap(fir,sec); if(sta[sec]==1) swap(fir,sec); cout<<name[fir]<<' '<<name[sec]<<endl; } } } return 0; } /* 2 Propus testdata 4 Tejat anything 6 statements anything testdata 3 Alzir Dirah Tejat Propus Poll Mebsuta */