【问题描述】ios
咱们知道机器调度是计算机科学中一个很是经典的问题。调度问题有不少种,具体条件不一样,问题就不一样。如今咱们要处理的是两个机器的调度问题。算法
有两个机器A和B。机器A有n种工做模式,咱们称之为mode_0,mode_l,……,mode_n-1。一样,机器B有m种工做模式,咱们称之为mode_0,mode_1,……,mode_m-1。初始时,两台机器的工做模式均为mode_0。如今有k个任务,每一个工做均可以在两台机器中任意一台的特定的模式下被加工。例如,job0能在机器A的mode_3或机器B的mode_4下被加工,jobl能在机器A的mode_2或机器B的mode_4下被加工,等等。所以,对于任意的jobi,咱们能够用三元组(i,x,y)来表示jobi在机器A的mode_x或机器B的mode_y下被加工。ide
显然,要完成全部工做,咱们须要不时的改变机器的工做模式。可是,改变机器的工做状态就必须重启机器,这是须要代价的。你的任务是,合理的分配任务给适当的机器,使机器的重启次数尽可能少。spa
【输入】string
第一行三个整数n,m(n,m<100),k(k<1000)。接下来的k行,每行三个整数i,x,y。it
【输出】io
只一行一个整数,表示最少的重启次数。class
【样例】stream
machine.in machine.out计算机科学
5 5 10 3
0 1 1
1 1 2
2 1 3
3 1 4
4 2 1
5 2 2
6 2 3
7 2 4
8 3 3
9 4 3
【问题分析】
本题所求的是工做模式的最少切换次数,实际上也就是求最少须要使用多少个工做模式,由于一个工做模式被切换两次确定是不合算的,一旦切换到一个工做模式就应该把这个工做模式能够完成的工做都完成。
将两台机器的工做模式分别当作n个和m个节点。jobi分别和机器A和B的mode_x和mode_y相关:jobi要被完成,就必须切换到机器A的mode_x或切换到机器B的mode_y。将jobi看做图中的一条边——链接节点x和节点y的边,那么这条边就要求x和y两个节点中至少要有一个节点被取出来。这正符合覆盖集的性质。
咱们构成的图是二分图,要求最少的切换次数,就是要使覆盖集最小。二分图的最小覆盖集问题等价于二分图的最大匹配问题。所以,只需对此二分图求一个最大匹配便是咱们要求的答案。时间复杂度。
//二部图 匈牙利算法 #include<cstdio> #include<iostream> #include<cstring> #define M 30 using namespace std; int g[M][M],link[M],used[M],n,m,k; int path(int i) { if(used[i])return 0; used[i]=1; for(int j=1;j<=m;j++) if(g[i][j]&&(!link[j]||path(link[j]))) { link[j]=i; return 1; } return 0; } int main() { scanf("%d%d%d",&n,&m,&k); for(int i=1;i<=k;i++) { int temp,x,y; scanf("%d%d%d",&temp,&x,&y); if(x&&y)g[x][y]=1; } for(int i=1;i<=n;i++) if(path(i)) memset(used,0,sizeof(used)); int tot=0; for(int i=1;i<=m;i++) if(link[i])tot++; printf("%d",tot); return 0; }