[Offer收割]程式設計練習賽2 hihocoder 1273 (DFS + 狀壓)

_TCgogogo_發表於2016-03-14
時間限制:5000ms
單點時限:1000ms
記憶體限制:256MB

描述

小Hi實驗室所在的建築一樓有一個用於貼海報的黑板,不停的有新的海報往上貼,也會安排人員不斷的對海報進行清理,而最近,輪到了小Hi去對海報進行清理。

黑板是一塊W*H大小的區域,如果以左下角為直角座標系的話,在上次清理後第i張貼上去的海報可以視作左下角為(X1i, Y1i),右上角為(X2i, Y2i)的一個矩形。

撕去一張海報會導致所有覆蓋在其上的海報都被同時撕掉(這樣被稱為連帶,這個過程是具有傳遞性的,即如果A覆蓋B,B覆蓋C,那麼撕掉C會導致A和B均被撕掉),但是一張海報想要被手動撕掉的話需要至少存在一個角沒有被其他海報覆蓋(海報A被海報B覆蓋當且僅當他們存在面積大於0的交集並且A在B之前貼出,海報A的一個角被海報B覆蓋當且僅當這個頂點處於海報B的內部)。

於是現在問題來了,為了節約時間,小Hi決定一次性撕掉儘可能多的海報,那麼他應該選擇哪張海報呢?在效果相同的情況下,小Hi傾向於選擇更早貼出的海報。

輸入

每個輸入檔案僅包含單組測試資料。

每組測試資料的第一行為三個正整數W,H和N,分別表示黑板的寬、高以及目前張貼出的海報數量。

接下來的N行,每行為四個正整數X1i、Y1i、X2i和Y2i,描述第i張貼出的海報。

對於20%的資料,滿足1<=N<=5,1<=W,H<=10

對於100%的資料,滿足1<=N<=1000,0<=X1i, X2i <= W, 0<=Y1i, Y2i<=H, 1<=W,H<=108

輸出

對於每組測試資料,輸出兩個正整數Ans和K,表示小Hi一次最多能撕掉多少張海報,和他選擇的海報是第幾張貼出的。

樣例輸入
6 7 4
0 0 4 4
1 0 3 4
1 4 4 6
0 0 3 5
樣例輸出
3 1

題目連結:http://hihocoder.com/problemset/problem/1273

題目分析:列舉面與面之間的覆蓋關係,用vector存,然後計算撕從開始到結束的每張海報一次能撕掉多少,這裡要注意當前海報的四個角都被覆蓋的情況,用狀態壓縮來記錄即可

#include <cstdio>
#include <cstring>
#include <algorithm>
#include <vector>
using namespace std;
int const MAX = 1e3 + 5;
int w, h, n;
int x1[MAX], y1[MAX], x2[MAX], y2[MAX];
int cnt[MAX];
vector<int> vt[MAX];

int Cal(int i, int j) 
{
    int res = 0;
    if(x1[i] > x1[j] && x1[i] < x2[j] && y1[i] > y1[j] && y1[i] < y2[j])
        res |= 1;
    if(x1[i] > x1[j] && x1[i] < x2[j] && y2[i] > y1[j] && y2[i] < y2[j])
        res |= 2;
    if(x2[i] > x1[j] && x2[i] < x2[j] && y2[i] > y1[j] && y2[i] < y2[j])
        res |= 4;
    if(x2[i] > x1[j] && x2[i] < x2[j] && y1[i] > y1[j] && y1[i] < y2[j])
        res |= 8;
    return res;
}

void DFS(int st, int u, int &sta) 
{
    cnt[u] = 1;
    int sz = vt[u].size();
    for(int i = 0; i < sz; i++) 
    {
        int v = vt[u][i];
        if(!cnt[v])
        {
            sta |= Cal(st, v);
            DFS(st, v, sta);
        }
    }
}

int main() 
{
    int min_x, max_x, min_y, max_y;
    scanf("%d %d %d", &w, &h, &n);
    for(int i = 1; i <= n; i++) 
        scanf("%d %d %d %d", &x1[i], &y1[i], &x2[i], &y2[i]);
    for(int i = 1; i <= n; i++)
    {
        for(int j = i + 1; j <= n; j++)
        {
            min_x = max(x1[i], x1[j]);
            max_x = min(x2[i], x2[j]);
            min_y = max(y1[i], y1[j]);
            max_y = min(y2[i], y2[j]);
            if(min_x < max_x && min_y < max_y)
                vt[i].push_back(j);
        }
    }
    int ans = 0, id = 0;
    for(int i = 1; i <= n; i++) 
    {
        int sta = 0;
        memset(cnt, 0, sizeof(cnt));
        DFS(i, i, sta);
        if(sta == 15) 
            continue;
        int cur = 0;
        for(int j = 1; j <= n; j++) 
            cur += cnt[j];
        if(cur > ans) 
        {
            ans = cur;
            id = i;
        }
    }
    printf("%d %d\n", ans, id);
}


相關文章