二分圖最小路徑覆蓋--poj2060 Taxi Cab Scheme

Taxi Cab Scheme

時間限制: 1 Sec  內存限制: 64 MB

題目描述

Running a taxi station is not all that simple. Apart from the obvious demand for a centralised coordination of the cabs in order to pick up the customers calling to get a cab as soon as possible,there is also a need to schedule all the taxi rides which have been booked in advance.Given a list of all booked taxi rides for the next day, you want to minimise the number of cabs needed to carry out all of the rides. For the sake of simplicity, we model a city as a rectangular grid. An address in the city is denoted by two integers: the street and avenue number. The time needed to get from the address a, b to c, d by taxi is |a - c| + |b - d| minutes. A cab may carry out a booked ride if it is its first ride of the day, or if it can get to the source address of the new ride from its latest,at least one minute before the new ride's scheduled departure. Note that some rides may end after midnight.node

給你N個出租車的預約單表,有初始時間,起點和終點。問最少用多少輛出租車能夠知足這N個預訂單。ios

輸入

On the first line of the input is a single positive integer N, telling the number of test scenarios to follow. Each scenario begins with a line containing an integer M, 0 < M < 500, being the number of booked taxi rides. The following M lines contain the rides. Each ride is described by a departure time on the format hh:mm (ranging from 00:00 to 23:59), two integers a b that are the coordinates of the source address and two integers c d that are the coordinates of the destination address. All coordinates are at least 0 and strictly smaller than 200. The booked rides in each scenario are sorted in order of increasing departure time.算法

輸出

For each scenario, output one line containing the minimum number of cabs required to carry out all the booked taxi rides.網絡

樣例輸入

2 2 08:00 10 11 9 16 08:07 9 16 10 11 2 08:00 10 11 9 16 08:06 9 16 10 11

樣例輸出

1 2

提示

 

 一樣的轉化爲圖G=(V,E),則問題轉化爲:

在圖G中選取儘量少的點,使得圖中每一條邊至少有一個端點被選中。

這個問題在二分圖問題中被稱爲最小點覆蓋問題。即用最少的點去覆蓋全部的邊。

結論:由König定理可知最小點覆蓋的點數 = 二分圖最大匹配ide



    König定理是一個二分圖中很重要的定理,它的意思是,一個二分圖中的最大匹配數等於這個圖中的最小點覆蓋數。若是你還不知道什麼是最小點覆蓋,我也在這裏說一下:假如選了一個點就至關於覆蓋了以它爲端點的全部邊,你須要選擇最少的點來覆蓋全部的邊。好比,下面這個圖中的最大匹配和最小點覆蓋已分別用藍色和紅色標註。它們都等於3。這個定理相信大多數人都知道,可是網絡上給出的證實並很少見。有一些網上常見的「證實」明顯是錯誤的。所以,我在這裏寫一下這個定理的證實,但願對你們有所幫助。


    假如咱們已經經過匈牙利算法求出了最大匹配(假設它等於M),下面給出的方法能夠告訴咱們,選哪M個點能夠覆蓋全部的邊。

    匈牙利算法須要咱們從右邊的某個沒有匹配的點,走出一條使得「一條沒被匹配、一條已經匹配過,再下一條又沒匹配這樣交替地出現」的路(交錯軌,增廣路)。可是,如今咱們已經找到了最大匹配,已經不存在這樣的路了。換句話說,咱們能尋找到不少可能的增廣路,但最後都以找不到「終點是尚未匹配過的點」而失敗。咱們給全部這樣的點打上記號:從右邊的全部沒有匹配過的點出發,按照增廣路的「交替出現」的要求能夠走到的全部點(最後走出的路徑是不少條不完整的增廣路)。那麼這些點組成了最小覆蓋點集:右邊全部沒有打上記號的點,加上左邊已經有記號的點。看圖,右圖中展現了兩條這樣的路徑,標記了一共6個點(用 「√」表示)。那麼,用紅色圈起來的三個點就是咱們的最小覆蓋點集。

    首先,爲何這樣獲得的點集點的個數剛好有M個呢?答案很簡單,由於每一個點都是某個匹配邊的其中一個端點。若是右邊的哪一個點是沒有匹配過的,那麼它早就當成起點被標記了;若是左邊的哪一個點是沒有匹配過的,那就走不到它那裏去(不然就找到了一條完整的增廣路)。而一個匹配邊又不可能左端點是標記了的,同時右端點是沒標記的(否則的話右邊的點就能夠通過這條邊到達了)。所以,最後咱們圈起來的點與匹配邊一一對應。

    其次,爲何這樣獲得的點集能夠覆蓋全部的邊呢?答案一樣簡單。不可能存在某一條邊,它的左端點是沒有標記的,而右端點是有標記的。緣由以下:若是這條邊不屬於咱們的匹配邊,那麼左端點就能夠經過這條邊到達(從而獲得標記);若是這條邊屬於咱們的匹配邊,那麼右端點不多是一條路徑的起點,因而它的標記只能是從這條邊的左端點過來的(想一想匹配的定義),左端點就應該有標記。

    最後,爲何這是最小的點覆蓋集呢?這固然是最小的,不可能有比M還小的點覆蓋集了,由於要覆蓋這M條匹配邊至少就須要M個點(再次回到匹配的定義)。

    證完了。
 
題解:

這道題乍一看不知道怎麼作,可是仔細想想,就能夠發現若是一輛車能夠在另一個乘客出發以前趕到出發點,就能夠將這兩個乘客之間連一條單向邊,從而能夠用二分圖來解決。
題目中的小時和分鐘混在了一塊兒,比較煩人,可是能夠將小時化成分鐘,再定義一個函數來求時間就能夠了。
 
#include<iostream>
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<algorithm>
#include<cmath>
#include<queue>
#include<stack>
#include<ctime>
using namespace std;
int n,t;
struct node
{
    int time,time2;
    int x1,y1,x2,y2;
}a[501];
int f[501][501],match[501],vis[501],dfscnt;
int suan(int x1,int y1,int x2,int y2)
{
    return abs(x2-x1)+abs(y2-y1);
}
bool dfs(int root)
{
    int i;
    for(i=1;i<=n;i++)
    {
        if(f[root][i])
        {
            if(vis[i]!=dfscnt)
            {
                vis[i]=dfscnt;
                if(!match[i]||dfs(match[i]))
                {
                    match[i]=root;
                    return 1;
                }
            }
        }
    }
    return 0;
}
int main()
{
    int i,j;
    scanf("%d",&t);
    while(t--)
    {
        memset(f,0,sizeof(f));
        memset(match,0,sizeof(match));
        memset(vis,0,sizeof(vis));
        dfscnt=0;
        scanf("%d",&n);
        for(i=1;i<=n;i++)
        {
            int hour,minute;
            scanf("%d:%d",&hour,&minute);
            a[i].time=hour*60+minute;
            scanf("%d%d%d%d",&a[i].x1,&a[i].y1,&a[i].x2,&a[i].y2);
            a[i].time2=a[i].time+suan(a[i].x1,a[i].y1,a[i].x2,a[i].y2);
        }
        for(i=1;i<=n;i++)
        {
            for(j=i;j<=n;j++)
            {
                if(a[i].time2+suan(a[i].x2,a[i].y2,a[j].x1,a[j].y1)<a[j].time)
                f[i][j]=1;
            }
        }
        int ans=0;
        for(i=1;i<=n;i++)
        {
            dfscnt++;
            if(dfs(i))ans++;
        }
        printf("%d\n",n-ans);
    }
}
相關文章
相關標籤/搜索