hdu 1083
2016-05-04 21:32
218 查看
题目概述:
有times组数据
有P个课程,N个人
每个课程可由times(和上面的不是一个变量)个人学,可学的人编号为num
输入:
第一行times(组数据),下一行P,N,其后P行,每行一个times(个人),其后times个num
输入共有times组
限制:
1<=P<=100;1<=N<=300;0<=times(个人)<=N;1<=num<=N;
输出:
每行一个字符串,如果每个课都有学生学,而每个学生至多学一门课,则为
YES
否则为
NO
多组输出之间没有空行
样例输入:
3
3 3
3 1 2 3
2 1 2
1 1
3 3
2 1 3
2 1 3
1 1
1 2
1 1
样例输出:
YES
NO
YES
讨论:
不难看出这就是个二分图匹配,课程-学生
其实这里可以进行一点小小的优化,一个是当课程数量多于学生数量时,由于每个学生至多选一门课,因此必然有课无法被选,另外,在进行匈牙利时,可以不用记录cnt,如果无法为某个课分配任何学生,也可以直接出结果
虽然匈牙利算法的实质是不断找增广路(从未匹配的点出发,依次经过匹配边,未匹配边……直到途径一个未匹配的点,则此路径为增广路),但额更倾向于理解为一个“让”的过程,能让则让,让不了就真的无法匹配了
1.这里牵扯到一个递归,如果该学生尚未选过课,那么当前的课就归这个学生,如果曾经选过课,则递归到那个课,尝试为那个课找一个别的学生,由于marked数组的存在,因此那个课不会再分配到刚才的那个学生,而是从其他学生里找一个替换,因此为每个课分配的学生是在不断更新的而非一成不变
题解状态:
265MS,1744K,1164 B,C++
EOF
有times组数据
有P个课程,N个人
每个课程可由times(和上面的不是一个变量)个人学,可学的人编号为num
输入:
第一行times(组数据),下一行P,N,其后P行,每行一个times(个人),其后times个num
输入共有times组
限制:
1<=P<=100;1<=N<=300;0<=times(个人)<=N;1<=num<=N;
输出:
每行一个字符串,如果每个课都有学生学,而每个学生至多学一门课,则为
YES
否则为
NO
多组输出之间没有空行
样例输入:
3
3 3
3 1 2 3
2 1 2
1 1
3 3
2 1 3
2 1 3
1 1
1 2
1 1
样例输出:
YES
NO
YES
讨论:
不难看出这就是个二分图匹配,课程-学生
其实这里可以进行一点小小的优化,一个是当课程数量多于学生数量时,由于每个学生至多选一门课,因此必然有课无法被选,另外,在进行匈牙利时,可以不用记录cnt,如果无法为某个课分配任何学生,也可以直接出结果
虽然匈牙利算法的实质是不断找增广路(从未匹配的点出发,依次经过匹配边,未匹配边……直到途径一个未匹配的点,则此路径为增广路),但额更倾向于理解为一个“让”的过程,能让则让,让不了就真的无法匹配了
1.这里牵扯到一个递归,如果该学生尚未选过课,那么当前的课就归这个学生,如果曾经选过课,则递归到那个课,尝试为那个课找一个别的学生,由于marked数组的存在,因此那个课不会再分配到刚才的那个学生,而是从其他学生里找一个替换,因此为每个课分配的学生是在不断更新的而非一成不变
题解状态:
265MS,1744K,1164 B,C++
#include<algorithm> #include<string.h> #include<stdio.h> #include<vector>//这里纯属多余,本打算用邻接表,但由于要判断是否存在路所以改用邻接矩阵 using namespace std; #define INF 0x3f3f3f3f #define maxx(a,b) ((a)>(b)?(a):(b)) #define minn(a,b) ((a)<(b)?(a):(b)) #define MAXN 305 int P,N;//实际上P并没有全局的必要,只是为了统一形式而已 bool edges[104][MAXN];//由于课只有100个,开到104足以 bool marked[MAXN];//编号为下标的学生在为某课分配学生时是否已使用过 int edgeto[MAXN];//下标为学生编号,值为课程编号 bool hungary(int a)//find已有该函数,改用匈牙利的英文hungary { for (int p = 1; p <= N; p++) {//遍历所有学生 if (edges[a][p] && !marked[p]) {//如果该课可被该学生选并且该学生在此轮选课中尚未使用过 marked[p] = true;//该学生现在已经被使用 if (!edgeto[p] || hungary(edgeto[p])) {//参见讨论1 edgeto[p] = a;//为该课程分配(重新分配)学生 return true;//完成一次选课 } } } return false;//选课没有完成,该课程无法被任何学生选 } void fun()//由于N和P都是全局的,所以不需要任何参数 { for (int p = 1; p <= P; p++) { int times; scanf("%d", ×);//input while (times--) { int num; scanf("%d", &num);//input//并不用在意课程号和学生号重复的现象,因为分别对应矩阵的横坐标和纵坐标,二者也不存在会混淆的地方 edges[p][num] = true; } }//input ends here int cnt = 0;//记录成功找到匹配的个数 for (int p = 1; p <= P; p++) { memset(marked, 0, sizeof(marked));//所谓选课与否是相对于为当前课程分配学生时,因此每次需要清空 if (hungary(p)) cnt++;//每次匈牙利成功找到匹配便加1 } if (cnt == P)//所有课程都有对应学生 printf("YES\n");//output else printf("NO\n");//output } int main(void) { //freopen("vs_cin.txt", "r", stdin); //freopen("vs_cout.txt", "w", stdout); int times; scanf("%d", ×); while (times--) { scanf("%d%d", &P, &N);//input fun(); memset(edgeto, 0, sizeof(edgeto));//有必要清空,谁也不希望被前人分配的结果混淆 memset(edges, 0, sizeof(edges));//有必要清空,修改课的可分配情况时并没有对所有情况进行更新 } }
EOF
相关文章推荐
- FZU 2039 Pets【二分匹配】
- java IO异常处理方式
- NIO边看边记 之 DatagramChannel(十)
- Android自动化压力测试之Monkey Test 异常解读(五)
- 杭电1712-分组背包问题
- NYOJ 38 布线问题
- Caffe学习笔记(一)——Windows 下caffe安装与配置
- A*算法解决八数码问题
- 测试报告
- web MVC 思想模式解读(图示)
- 【步兵 c++】 多态&模板
- Leetcode 113. Path Sum II
- 土地利用分类详细教程——以高分一号影像为例(上)
- boost中regex使用时出现的问题
- ACM:数论专题——拓展欧几里得
- Xutils,Xutils3的使用方法
- HDU 1022 Train Problem I
- 杭电2159-二维费用的背包问题
- Java回调机制(异步)
- 第六周项目二-带武器的游戏角色