(感觉是一个比较基础的求二分图必须边)
题目意思大概为给几个范围N,再给几个点M,如果点在范围内,就相当于可以匹配在一起,最后求必须边
首先把范围和在范围内的点连接在一起,即所有边都连接范围与点,所以是二分图
然后对于每个范围N遍历,将该范围i与其有边相连的点j连接在一起,然后在二分图匹配,若完美匹配的数量大于2,则说明没有必须边,若等于0,则说明不能完美匹配,若等于1,则说明存在必须边,输出范围i和点j
(也可以进行删边后匹配)
最后若是一个必须边都没有,则输出none
其他细节我注释在代码里
【这个输出需要仔细(没仔细看,被卡到wa了十几次),题目意思为有必须边,就输出该必须边,若一个必须边都没有,才输出none】
给个样例:
输入:
3
0 2 0 2
0 2 0 2
0 4 0 4
1 1
1 1
3 3
Heap 1
(C,3)
#include <iostream>
#include <stdio.h>
#include <string.h>
#include <vector>
using namespace std;
vector<int> data[105];
int N;
int match[105];
int jg[105]; //记录必须边
bool used[105];
void add_edge(int from, int to)
{
data[from].push_back(to);
data[to].push_back(from);
}
bool dfs(int v)
{
used[v] = true;
for(int i = 0; i < data[v].size(); i++)
{
int u = data[v][i], w = match[u];
if(w == -1 || !used[w] && dfs(w))
{
match[u] = v;
match[v] = u;
return true;
}
}
return false;
}
int main()
{
int x_min[55], x_max[55], y_min[55], y_max[55];
int f = 1;
while(1)
{
for(int i = 0; i < 105; i++)
{
data[i].clear();
}
scanf("%d", &N);
if(N == 0)
{
break;
}
for(int i = 0; i < N; i++)
{
scanf("%d %d %d %d", &x_min[i], &x_max[i], &y_min[i], &y_max[i]);
}
for(int j = 0; j < N; j++)
{
int x, y;
scanf("%d %d", &x, &y);
for(int i = 0; i < N; i++)
{
if(x < x_max[i] && x > x_min[i] && y < y_max[i] && y > y_min[i])
{
add_edge(i, N + j);
}
}
}
bool flag = true, fff = true;
printf("Heap %d\n", f++);
for(int i = 0; i < N; i++)
{
int r = 0; //该范围i完美匹配的次数
for(int j = 0; j < data[i].size(); j++)
{
int res = 1; //因为已经把范围i和点j连接在了一起,所以初始为1
memset(match, -1, sizeof(match));
match[i] = data[i][j]; //对于每个边进行遍历,连接后再二分图匹配
match[data[i][j]] = i;
for(int k = 0; k < N; k++)
{
if(k == i)
{
continue;
}
memset(used, 0, sizeof(used));
used[i] = true; //防止边被改变,让范围i不再被递归到
if(dfs(k))
{
res++;
}
}
if(res == N)
{
r++;
jg[i] = data[i][j]; //记录边
}
}
if(r == 1)
{
if(!fff)
{
printf(" ");
}
printf("(%c,%d)", 'A' + i, jg[i] - N + 1);
fff = false;
}
}
if(fff)
{
printf("none");
}
printf("\n\n");
}
}