hdu 3663 Power Stations(精確覆蓋 Dancing Links 模版)

Power Stations

Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 1899    Accepted Submission(s): 514
Special Judge


Problem Description
There are N towns in our country, and some of them are connected by electricity cables. It is known that every town owns a power station. When a town’s power station begins to work, it will provide electric power for this town and the neighboring towns which are connected by cables directly to this town. However, there are some strange bugs in the electric system –One town can only receive electric power from no more than one power station, otherwise the cables will be burned out for overload.

The power stations cannot work all the time. For each station there is an available time range. For example, the power station located on Town 1 may be available from the third day to the fifth day, while the power station on Town 2 may be available from the first day to the forth day. You can choose a sub-range of the available range as the working time for each station. Note that you can only choose one sub-range for each available range, that is, once the station stops working, you cannot restart it again. Of course, it is possible not to use any of them.

Now you are given all the information about the cable connection between the towns, and all the power stations’ available time. You need to find out a schedule that every town will get the electricity supply for next D days, one and only one supplier for one town at any time.
 

Input
There are several test cases. The first line of each test case contains three integers, N, M and D (1 <= N <= 60, 1 <= M <= 150, 1 <= D <= 5), indicating the number of towns is N, the number of cables is M, and you should plan for the next D days.

Each of the next M lines contains two integers a, b (1 <= a, b <= N), which means that Town a and Town b are connected directly. Then N lines followed, each contains two numbers si and ei, (1 <= si <= ei <= D) indicating that the available time of Town i’s power station is from the si-th day to the ei-th day (inclusive).
 

Output
For each test case, if the plan exists, output N lines. The i-th line should contain two integers ui and vi, indicating that Town i’s power station should work from the ui-th day to vi-day (inclusive). If you didn’t use this power station at all, set ui = vi = 0.

If the plan doesn’t exist, output one line contains “No solution” instead.

Note that the answer may not be unique. Any correct answers will be OK.

Output a blank line after each case.
 

Sample Input
3 3 5 1 2 2 3 3 1 1 5 1 5 1 5 4 4 5 1 2 2 3 3 4 4 1 1 5 1 5 1 5 1 5
 

Sample Output
1 5 0 0 0 0 No solution

題目描述:

有n個城市,還有m條邊(雙向),每個城市都有一個發電站,如果一個發電站工作,它能夠給它所在的城市和直接相鄰的城市提供電力。並且要求每個城市只能由一個發電站來提供電力(即不能夠被兩個或以上的發電站同時覆蓋)。

然後,每個城市的發電站都有一個允許工作時間 ai bj,表示發電站只能在[ai,bi]內的某個連續區間內工作(也可以一個都不選),並且只能選一個區間(即ai = 1, bi = 5, 不能選擇1-2 和4-5兩個區間)。

然後給你一個數字D,問你能不能安排這n個發電站的工作時間使1~D的時間區間內,每個城市在每個時間都能夠被一個發電站覆蓋。

可以的話輸出任意一種解決方法。

n <= 60, m<= 150, D<=5

解題報告:

初看題意,是一個覆蓋問題,n又很小,搜,怎麼搜,DLX的精確覆蓋模型。

精確覆蓋:一個0,1矩陣,選擇某些行,使每一列都有且僅有一個1。即用行覆蓋列。

行的定義:

一共n * 16行,16就是[1,5]區間的所有小區間:

{{1, 1}, {1, 2}, {1, 3}, {1, 4}, {1, 5},

{2, 2}, {2, 3}, {2, 4}, {2, 5},

{3, 3}, {3, 4}, {3, 5},

{4, 4}, {4, 5},

{5, 5}, {0, 0}};

其中0,0表示不用。

這樣第(i – 1) * 16 + j就表示第i個發電站選擇小區間j時狀態。

(1 <= i <= n, 1 <= j <= 16)

列的定義:

對於第(a – 1) * 16 + b行,一共有n * d + n列。

第(i – 1) * d + j列表示第i個城市的第j天 是否被這一行的狀態(a發電站選擇b區間)供電,

第n * d + j列爲1表示這個覆蓋來自第j個發電站(因爲每個發電站只能用一次,所以要用額外的n列來限制,和數獨那題的解法類似,由於這n列每一列只能被覆蓋一次,就限制了使用次數也是1)。

這樣圖就建好了,套用DLX模板即可。有界的話就輸出一個就好了。

AC代碼:
#include <cstdio>
#include <cstring>
#include <iostream>
#include <cmath>
#include <algorithm>
#include <vector>
#include <bitset>
#include <queue>
#define ll long long
using namespace std;

const int maxn = 60 * 20;
const int maxm = 60 * 10;
const int max_size = maxn * maxm;
const int INF = 1e9;

int L[max_size], R[max_size], U[max_size], D[max_size], CH[max_size], RH[max_size];
int S[max_size], O[max_size];
int head, size;
int n, m, d, len;
vector<int> G[100];
int st[100], ed[100], ans[100];
bool mat[maxn][maxm];
int move[16][2] = {{1, 1}, {1, 2}, {1, 3}, {1, 4}, {1, 5},
                         {2, 2}, {2, 3}, {2, 4}, {2, 5},
                                 {3, 3}, {3, 4}, {3, 5},
                                         {4, 4}, {4, 5},
                                                 {5, 5}, {0, 0}};
int node(int up, int down, int left, int right) {
    U[size] = up, D[size] = down;
    L[size] = left, R[size] = right;
    D[up] = U[down] = R[left] = L[right] = size;
    return size++;
}

void init(int N, int M) {
    size = 0;
    head = node(0, 0, 0, 0);
    for (int j = 1; j <= M; ++j) {
        CH[j] = node(size, size, L[head], head), S[j] = 0;
    }
    for (int i = 1; i <= N; ++i) {
        int row = -1, k;
        for (int j = 1; j <= M; ++j) {
            if (!mat[i][j]) continue;
            if (row == -1) {
                row = node(U[CH[j]], CH[j], size, size);
                RH[row] = i, CH[row] = CH[j], ++S[j];
            } else {
                k = node(U[CH[j]], CH[j], L[row], row);
                RH[k] = i, CH[k] = CH[j], ++S[j];
            }
        }
    }
}
void remove(const int &c) {
    L[R[c]] = L[c], R[L[c]] = R[c];
    for (int i = D[c]; i != c; i = D[i]) {
        for (int j = R[i]; j != i; j = R[j]) {
            U[D[j]] = U[j], D[U[j]] = D[j];
            --S[CH[j]];
        }
    }
}
void resume(const int &c) {
    for (int i = U[c]; i != c; i = U[i]) {
        for (int j = L[i]; j != i; j = L[j]) {
            ++S[CH[j]];
            U[D[j]] = D[U[j]] = j;
        }
    }
    L[R[c]] = R[L[c]] = c;
}
bool dance(const int &k) {
    if (R[head] == head) {
        len = k - 1;
        return true;
    }
    int s = INF, c;
    for (int t = R[head]; t != head; t = R[t]) {
        if (S[t] < s) s = S[t], c = t;
    }
    remove(c);
    for (int i = D[c]; i != c; i = D[i]) {
        O[k] = RH[i];
        for (int j = R[i]; j != i; j = R[j]) {
            remove(CH[j]);
        }
        if (dance(k + 1)) {
            return true;
        }
        for (int j = L[i]; j != i; j = L[j]) {
            resume(CH[j]);
        }
    }
    resume(c);
    return false;
}
int main()
{
    int a, b;
    while(~scanf("%d%d%d", &n, &m, &d))
    {
        for(int i = 1; i <= n; i++)
        {
            G[i].clear();
            G[i].push_back(i);
        }
        for(int i = 0; i < m; i++)
        {
            scanf("%d%d", &a, &b);
            G[a].push_back(b);
            G[b].push_back(a);
        }
        for(int i = 1; i <= n; i++)
        scanf("%d%d", &st[i], &ed[i]);
        memset(mat, 0, sizeof(mat));
        for(int i = 1; i <= n; i++)
        {
            for(int j = 0; j < 15; j++)
            {
                int x = (i - 1) * 16 + j + 1;
                if(move[j][0] >= st[i] && move[j][1] <= ed[i])
                {
                    for(int k = 0; k < (int) G[i].size(); k++)
                    {
                        int v = G[i][k];
                        for(int l = move[j][0]; l <= move[j][1]; l++)
                        mat[x][(v - 1)* d + l] = 1;
                    }
                    mat[x][n * d + i] = 1;
                }
            }
            mat[(i - 1) * 16 + 16][n * d + i] = 1;
        }
        init(n * 16, n * d + n);
        dance(1);
        if(len != n) printf("No solution\n");
        else
        {
             for(int i = 1; i <= len; i++)
            {
                int tmp = ((O[i] - 1) / 16) + 1;
                int tmp2 = O[i] - (tmp - 1) * 16 - 1;
                ans[tmp] = tmp2;
            }
            for(int i = 1; i <= n; i++)
                printf("%d %d\n", move[ans[i]][0], move[ans[i]][1]);
        }
        puts("");
    }
    return 0;
}


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章