【问题描述】
我们知道机器调度是计算机科学中一个非常经典的问题。调度问题有很多种,具体条件不同,问题就不同。现在我们要处理的是两个机器的调度问题。
有两个机器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下被加工。
显然,要完成所有工作,我们需要不时的改变机器的工作模式。但是,改变机器的工作状态就必须重启机器,这是需要代价的。你的任务是,合理的分配任务给适当的机器,使机器的重启次数尽量少。
【输入】
第一行三个整数n,m(n,m<100),k(k<1000)。接下来的k行,每行三个整数i,x,y。
【输出】
只一行一个整数,表示最少的重启次数。
【样例】
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; }