ZOJ: http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemCode=1197
POJ: http://poj.org/problem?id=1486
题目大意:
有一些透明的幻灯片乱放成一大堆。每张幻灯片上写有编号,但是透明的幻灯片叠在一起,看不清楚每个数字是写在哪一张上的。
例如题图中,用字母A,B,C,D给幻灯片编号,可以推测出D上写有3,B上写有1,C上写有2,A上写有4。
解题思路:
幻灯用A..Z表示,那么n最大只有26。根据幻灯坐标范围和数字坐标建立二分图。
对于每张幻灯片,每次删掉和一个数字的连边(如果有),如果仅有某一条边可以使余下边的最大匹配为n-1,则字母和数字配对唯一。
又没有注意到“Output a blank line after each test case.”,又PE了,想拿板砖拍死自己……
源代码:
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <algorithm>
using namespace std;
#define maxn 30
bool MaxMatchDFS(bool g[][maxn], int m, int a, int y[], bool u[])
{
for (int i=0; i<m; i++)
if (!u[i] && g[a][i])
{
int t=y[i];
u[i]=true; y[i]=a;
if (t==-1 || MaxMatchDFS(g, m, t, y, u)) return true;
y[i]=t;
}
return false;
}
int MaxMatch(bool g[][maxn], int n, int m) //v1[y[i]] matches v2[i]
{
int y[maxn];
memset(y, 255, sizeof(y));
int c=0;
for (int i=0; i<n; i++)
{
bool u[maxn]={0};
if (MaxMatchDFS(g, m, i, y, u)) c++;
}
return c;
}
bool init(bool g[][maxn], int &n)
{
int xmin[maxn], xmax[maxn], ymin[maxn], ymax[maxn];
int x[maxn], y[maxn];
scanf("%d", &n);
if (n==0) return false;
for (int i=0; i<n; i++)
scanf("%d%d%d%d", &xmin[i], &xmax[i], &ymin[i], &ymax[i]);
for (int i=0; i<n; i++)
scanf("%d%d", &x[i], &y[i]);
memset(g, false, sizeof(*g)*maxn);
for (int i=0; i<n; i++)
for (int j=0; j<n; j++)
{
if (xmin[i]<x[j] && xmax[i]>x[j]
&& ymin[i]<y[j] && ymax[i]>y[j])
g[i][j]=1;
}
return true;
}
int main()
{
int cs=0;
int n, unique, match;
bool g[maxn][maxn];
bool found;
while (init(g, n))
{
found=false;
printf("Heap %d\n", ++cs);
for (int i=0; i<n; i++)
{
unique=-1; //0:false 1:true -1:don't know
match=-1;
for (int j=0; j<n; j++)
if (g[i][j])
{
g[i][j]=false;
if (MaxMatch(g, n, n)==n-1)
{
if (unique==-1){unique=1;match=j;}
else {unique=0; break;}
}
g[i][j]=true;
}
if (unique==1)
{
if (found==false) found=true;
else printf(" ");
printf("(%c,%d)", i+'A', match+1);
}
}
if (found==false) printf("none\n\n");
else printf("\n\n");
}
return 0;
}