POJ 1325-Machine Schedule(二分圖匹配-匈牙利演算法)

kewlgrl發表於2016-08-17
Machine Schedule
Time Limit: 1000MS   Memory Limit: 10000K
Total Submissions: 14308   Accepted: 6107

Description

As we all know, machine scheduling is a very classical problem in computer science and has been studied for a very long history. Scheduling problems differ widely in the nature of the constraints that must be satisfied and the type of schedule desired. Here we consider a 2-machine scheduling problem. 

There are two machines A and B. Machine A has n kinds of working modes, which is called mode_0, mode_1, ..., mode_n-1, likewise machine B has m kinds of working modes, mode_0, mode_1, ... , mode_m-1. At the beginning they are both work at mode_0. 

For k jobs given, each of them can be processed in either one of the two machines in particular mode. For example, job 0 can either be processed in machine A at mode_3 or in machine B at mode_4, job 1 can either be processed in machine A at mode_2 or in machine B at mode_4, and so on. Thus, for job i, the constraint can be represent as a triple (i, x, y), which means it can be processed either in machine A at mode_x, or in machine B at mode_y. 

Obviously, to accomplish all the jobs, we need to change the machine's working mode from time to time, but unfortunately, the machine's working mode can only be changed by restarting it manually. By changing the sequence of the jobs and assigning each job to a suitable machine, please write a program to minimize the times of restarting machines. 

Input

The input file for this program consists of several configurations. The first line of one configuration contains three positive integers: n, m (n, m < 100) and k (k < 1000). The following k lines give the constrains of the k jobs, each line is a triple: i, x, y. 

The input will be terminated by a line containing a single zero. 

Output

The output should be one integer per line, which means the minimal times of restarting machine.

Sample Input

5 5 10
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
0

Sample Output

3

Source


題目意思:

有兩臺機器A和B,A有N種工作模式0~N-1,B有M種工作模式0~M-1,剛開始時的初始狀態,A和B都在模式0。
給定K個作業,每個作業可以工作在特定的A和B的模式下。樣例中,0 1 1 表示作業0可以工作在A的1狀態和B的1狀態。
為了完成作業,機器必須不斷的切換模式,試著寫程式實現:改變機器的順序,給每個作業分配合適的作業,使得重啟機器次數最少。

解題思路:

構造二部圖,用匈牙利演算法做二分圖匹配。

如果某作業任務可以在A的i狀態和B的j狀態上完成,則從Ai到Bj連一條邊,這樣構造二部圖。
對於樣例來說,選擇A狀態的1和2,B狀態的3。

DFS和BFS效率和記憶體幾乎完全一樣…

①DFS

#include <iostream>
#include <cstdio>
#include <cstring>
#include <vector>
#include <queue>
#include <algorithm>
#define maxn 1010
#define INF 0xfffffff
using namespace std;
int nx,ny;//X與Y集合中元素的個數
int g[maxn][maxn];//邊的鄰接矩陣
int cx[maxn],cy[maxn];//cx[i]表示最終求得的最大匹配中與Xi匹配的頂點,cy[i]同理

int mk[maxn];//mark,記錄頂點訪問狀態
int path(int u)
{
    //for(int v=0; v<ny; ++v)//A與B兩機器初始為0,所以0狀態不必重啟,從1開始
    for(int v=1; v<ny; ++v)//考慮Yi的頂點v
        if(g[u][v]&&!mk[v])//v與u鄰接,且沒有訪問過
        {
            mk[v]=1;//訪問v
            if(cy[v]==-1||path(cy[v]))//如果v沒有匹配,或者v已經匹配但是從cy[v]出發可以找到一條增廣路
            {
                cx[u]=v;//v匹配給u
                cy[v]=u;//u匹配給v
                return 1;//找到可增廣路
            }
        }
    return 0;//不存在從u出發的增廣路
}
int MaxMatch()//匈牙利演算法
{
    int res=0;//所求得的最大匹配
    memset(cx,-1,sizeof(cx));//從0開始匹配增廣,所以初始化為-1
    memset(cy,-1,sizeof(cy));
    // for(int i=0; i<=nx; ++i)
    for(int i=1; i<=nx; ++i)//A與B兩機器初始為0,所以0狀態不必重啟,從1開始
        if(cx[i]==-1)//從每個未蓋點出發進行尋找增廣路
        {
            memset(mk,0,sizeof(mk));
            res+=path(i);//每找到一條增廣路,可使得匹配數加1
        }
    return res;
}
int main()
{
    int k;
    while(cin>>nx&&nx!=0)
    {
        cin>>ny>>k;
        memset(g,0,sizeof(g));
        int i,a,x,y;
        for(i=0; i<k; ++i)
        {
            cin>>a>>x>>y;
            g[x][y]=1;
        }
        cout<<MaxMatch()<<endl;
    }
    return 0;
}
/*
5 5 10
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
0
*/

②BFS

#include <iostream>
#include <cstdio>
#include <cstring>
#include <vector>
#include <queue>
#include <algorithm>
#define maxn 1010
#define INF 0xfffffff
using namespace std;
int nx,ny;//X與Y集合中元素的個數
int g[maxn][maxn];//邊的鄰接矩陣
int cx[maxn],cy[maxn];//cx[i]表示最終求得的最大匹配中與Xi匹配的頂點,cy[i]同理

int pred[maxn];//用來記錄交錯軌,同時也記錄Y集合中的頂點是否遍歷過
int que[maxn];//陣列模擬佇列
int MaxMatch()
{
    int i,j,y;
    int cur,tail;//佇列首位位置的下標
    int res=0;//求得的最大匹配數
    memset(cx,-1,sizeof(cx));//初始化所有點為未被匹配的狀態
    memset(cy,-1,sizeof(cy));
    //for(i=0; i<nx; ++i)
    for(i=1; i<nx; ++i)//對X集合中的每個未蓋點i進行一次BFS找交錯軌
    {
        if(cx[i]!=-1) continue;
        //for(j=0; j<ny; ++j)
        for(j=1; j<ny; ++j)
            pred[j]=-2;//-2是初始值
        cur=tail=0;//初始化佇列
        //for(j=0; j<ny; ++j)
        for(j=1; j<ny; ++j)//i的鄰接頂點入佇列
            if(g[i][j])
            {
                pred[j]=-1;//-1表示遍歷到且是鄰接頂點
                que[tail++]=j;
            }
        while(cur<tail)
        {
            y=que[cur];
            if(cy[y]==-1) break;//找到一個未被匹配的點,則找到了一條交錯軌
            ++cur;
            //for(j=0; j<ny; ++j)
            for(j=1; j<ny; ++j)//y已經被匹配給cy[y]了,從cy[y]出發,將它的鄰接頂點入佇列
                if(pred[j]==-2&&g[cy[y]][j])
                {
                    pred[j]=y;
                    que[tail++]=j;
                }
        }
        if(cur==tail) continue;//沒有找到交錯軌
        while(pred[y]>-1)//更改交錯軌上的匹配狀態
        {
            cx[cy[pred[y]]]=y;
            cy[y]=cy[pred[y]];
            y=pred[y];
        }
        cy[y]=i;
        cx[i]=y;
        res++;
    }
    return res;
}
int main()
{
    int k;
    while(cin>>nx&&nx!=0)
    {
        cin>>ny>>k;
        memset(g,0,sizeof(g));
        int i,a,x,y;
        for(i=0; i<k; ++i)
        {
            cin>>a>>x>>y;
            g[x][y]=1;
        }
        cout<<MaxMatch()<<endl;
    }
    return 0;
}
/*
5 5 10
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
0
*/


相關文章