poj1486(二分图必须边)

56 阅读2分钟

(感觉是一个比较基础的求二分图必须边)

题目意思大概为给几个范围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");
    }
}