POJ1486_Sorting Slides_二分图匹配必须边

来源:互联网 发布:云网络验证 编辑:程序博客网 时间:2024/06/05 02:00

题意

一些透明的纸杂乱地摞在一起,从上往下依次用大写英文字母编号。每一张纸上都写着一个数字。现在给出纸的边框坐标和数字的坐标,试确定每张纸对应的数字是几。以成对形式输出确定对应的纸编号和数字。如果没有确定的对应,则输出none。

思路

一开始以为是一个简单的二分图模板,然而写出来样例都过不了
这里的“对应”并不是简单的匹配,而是一种确定关系。题意是说确定了某个数字一定在某一张纸上。然后就开始各种打补丁,然而还是没有AC。
看了网上的题解才知道,这种唯一的对应关系称为二分图匹配中的必须边。具体算法过程如下:
首先,根据题意,必定存在完美匹配。所以,先用二分图算法求出一个完美匹配。(这个结果令存一个数组)
然后对于这个完美匹配中的每一条边,在图中删除这条边,然后再进行二分图匹配。如果仍是完美匹配,说明这条边不是必须边,这两个点的关系也不是唯一的对应关系。如果不是完美匹配了,说明这条边是必须边。

题目链接

http://poj.org/problem?id=1486

AC代码

#include<cstdio>#include<iostream>#include<vector>#include<cstring>using namespace std;const int maxn = 300;int n;              //纸的数量int A[maxn][4];     //纸边缘坐标int B[maxn][2];     //数字坐标bool G[maxn][maxn]; //纸和数字抽象成点建图int res[maxn];      //一开始求出的完美匹配int match[maxn];bool usd[maxn];//二分图匹配模板bool dfs(int v){    usd[v] = true;    for(int i= n; i< 2*n; i++)    {        if(!G[v][i]) continue;        int u = i, w = match[u];        if(w < 0 || !usd[w] && dfs(w))        {            match[v] = u;            match[u] = v;            return true;        }    }    return false;}int max_match(){    int res = 0;    memset(match, -1, sizeof match);    for(int i= 0; i< n; i++)        if(match[i] < 0)    {        memset(usd, 0, sizeof usd);        if(dfs(i)) res ++;    }    return res;}//二分图匹配模板int main(){    for(int k= 1; ; k++)    {        scanf("%d", &n);        if(n == 0) break;        memset(G, false, sizeof G);        for(int i= 0; i< n; i++)            for(int j= 0; j< 4; j++)                cin >> A[i][j];        for(int i= 0; i< n; i++)            cin >> B[i][0] >> B[i][1];        for(int i= 0; i< n; i++)        {            for(int j= 0; j< n; j++)            {                if(A[i][0] < B[j][0] && A[i][1] > B[j][0]                    && A[i][2] < B[j][1] && A[i][3] > B[j][1])                {                    G[i][n+j] = G[n+j][i] = true;                }            }        }        max_match();        //另存完美匹配结果        for(int i= 0; i< n; i++)            res[i] = match[i];        int cnt = 0;//已找出的必须边数        printf("Heap %d\n", k);        for(int i= 0; i< n; i++)        {            G[i][res[i]] = G[res[i]][i] = false;//在图中删除边            if(n == max_match()) continue;//仍是完美匹配            else{                         //不是完美匹配了                if(cnt ++ > 0) printf(" ");                printf("(%c,%d)", i+'A', res[i]-n+1);            }            G[i][res[i]] = G[res[i]][i] = true;//判定完后恢复边        }        if(cnt == 0) printf("none");        cout << endl << endl;    }    return 0;}
原创粉丝点击