博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
POJ 1486 Sorting Slides (二分图关键匹配边)
阅读量:5173 次
发布时间:2019-06-13

本文共 3179 字,大约阅读时间需要 10 分钟。

题意

给你n个幻灯片,每个幻灯片有个数字编号1~n,现在给每个幻灯片用A~Z进行编号,在该幻灯片范围内的数字都可能是该幻灯片的数字编号。问有多少个幻灯片的数字和字母确定的。

思路

确定幻灯片的数字就是求完美匹配也就是最大匹配,而题目要求的边就是
匹配的关键边,也叫必须边,即任意一个最大匹配一定要包含这条边。
关键边求法: 先求一遍最大匹配,然后枚举删去匹配边,看之后的最大匹配是否减小,如果减小则该边是匹配关键边。 这让我想起了寻找关键割边:如果一个割边增加流量后整个最大流增加则该割边是关键割边。呵呵,是不是很像?算法的魅力之一就在于举一反三吧^_^~

代码

 
#include #include #include #include #include #include #include #define MID(x,y) ((x+y)/2)#define mem(a,b) memset(a,b,sizeof(a))using namespace std;const int MAXV = 55;                   //N1+N2vector  adj[MAXV];struct MaximumMatchingOfBipartiteGraph{    int vn;    void init(int n){                   //二分图两点集点的个数        vn = n;        for (int i = 0; i <= vn; i ++)     adj[i].clear();    }    void add_uedge(int u, int v){		adj[u].push_back(v);		adj[v].push_back(u);    }    bool vis[MAXV];    int mat[MAXV];                      //记录已匹配点的对应点    bool cross_path(int u){        for (int i = 0; i < (int)adj[u].size(); i ++){            int v = adj[u][i];            if (!vis[v]){                vis[v] = true;                if (mat[v] == 0 || cross_path(mat[v])){                    mat[v] = u;                    mat[u] = v;                    return true;                }            }        }        return false;    }    int hungary(){        mem(mat, 0);        int match_num = 0;        for (int i = 1; i <= vn; i ++){            mem(vis, 0);            if (!mat[i] && cross_path(i)){                match_num ++;            }        }        return match_num;    }}match;struct xy{    int x1, x2, y1, y2;    int x, y;}a[MAXV];bool del[MAXV][MAXV];void build(int n){    match.init(n+n);    for (int i = 1; i <= n; i ++){        for (int j = n+1; j <= n+n; j ++){            if (!del[i][j] && a[j].x >= a[i].x1 && a[j].x <= a[i].x2 && a[j].y >= a[i].y1 && a[j].y <= a[i].y2){                match.add_uedge(i, j);            }        }    }}map  key_match;int main(){	//freopen("test.in", "r", stdin);	//freopen("test.out", "w", stdout);	int n;	int t = 1;	while(scanf("%d", &n), n){        for (int i = 1; i <= n; i ++){            scanf("%d %d %d %d", &a[i].x1, &a[i].x2, &a[i].y1, &a[i].y2);        }        for (int i = 1; i <= n; i ++){            scanf("%d %d", &a[i+n].x, &a[i+n].y);        }        mem(del, false);        build(n);        int max_match = match.hungary();        key_match.clear();        for (int i = 1; i <= n; i ++){            key_match.insert(make_pair(i+64, match.mat[i]-n));        }        map  :: iterator it;        for (it = key_match.begin(); it != key_match.end(); it ++){            del[it->first - 64][it->second+n] = true;            build(n);            del[it->first - 64][it->second+n] = false;            int tmp_match = match.hungary();            if (tmp_match == max_match){                it->second = -1;            }        }        printf("Heap %d\n", t ++);        bool ok = 0;        for (it = key_match.begin(); it != key_match.end(); it ++){            if (it->second == -1)   continue;            ok = 1;            printf("(%c,%d) ", it->first, it->second);        }        if (ok){            puts("\n");        }        else{            puts("none\n");        }	}	return 0;}

转载于:https://www.cnblogs.com/AbandonZHANG/p/4114069.html

你可能感兴趣的文章
搜狗输入法安装--ubuntu
查看>>
ps/2接口键盘的输入及显示
查看>>
Swift———a Glance(极客学院)笔记
查看>>
【poj3294-不小于k个字符串中最长公共子串】后缀数组
查看>>
java如何获取其它用户登录的真是IP地址
查看>>
Jquery通过指定层次关系获取元素
查看>>
c# for 和 foreach 的区别
查看>>
docfx (一)
查看>>
HashMap底层实现原理/HashMap与HashTable区别/HashMap与HashSet区别
查看>>
深度学习之前馈神经网络(前向传播和误差反向传播)
查看>>
IEnumerable<T>和IQueryable<T>区别
查看>>
(转)MFC界面风格
查看>>
Centos7 tmux1.6 安装
查看>>
二叉树(三)
查看>>
linux加密文件系统 fsck 无法修复一例
查看>>
【linux配置】VMware安装Redhat6.5
查看>>
AI自主决策——有限状态机
查看>>
《http权威指南》阅读笔记(二)
查看>>
软件工程
查看>>
http协议
查看>>