hdu3663Power Stations(DLX解精確覆蓋)

題目請戳這裏

題目大意:一個國家有n個城市,每個城市有一個電站。n個城市之間有m條電線,通過電線相連的城市之間可以互相通電。現在給出每個城市發電站工作的時間段,要求使所有的城市在未來連續D小時都通電並且保證每個城市只能同時接受一個城市的電(或者自己發電),求每個城市發電站工作時間表,每個城市只能工作一個連續的時間段。

題目分析:點支配集轉精確覆蓋問題,DLX解決。由於所有城市在未來連續D小時都必須通電。所以每個城市抽象出D列,一共n*D列。對於每個城市,由於工作的時間段長度不超過5。所以每個城市發電站工作的時間段最多15種情況。所以每個城市抽象出15行,一共n*15行。然後根據城市之間的連線情況建圖,跑DLX算法即可。

對於每個城市發電站工作的時間段,一共15種情況,每種情況對應一個id,用一個二維數組保存。因爲每個城市只能工作一個連續的時間段,那麼在搜索過程中要進行判重。

詳情請見代碼:

#include <iostream>
#include<cstdio>
#include<cstring>
#include<map>
#include<algorithm>
using namespace std;
const int N = 61;
const int M = N * 15 * 6 * N + 10;

int n,m,D;
int s[M],h[M],u[M],d[M],l[M],r[M],col[M],row[M],ans[M],aans[N][3];
int num;
bool flag[N][N];
map<int,int>lcm;
bool vis[N];
bool ok;
int idx[6][6] = {
    {0,0,0,0,0,0},
    {0,1,0,0,0,0},
    {0,2,6,0,0,0},
    {0,3,7,10,0,0},
    {0,4,8,11,13,0},
    {0,5,9,12,14,15},
};
void init()
{
    int i,c;
    memset(h,0,sizeof(h));
    memset(s,0,sizeof(s));
    memset(vis,false,sizeof(vis));
    memset(flag,false,sizeof(flag));
    c = D * n;
    for(i = 0;i <= c;i ++)
    {
        u[i] = d[i] = i;
        l[i] = (i + c) % (c + 1);
        r[i] = (i + 1) % (c + 1);
    }
    num = c + 1;
    lcm.clear();
    lcm[1] = 11;
    lcm[2] = 12;lcm[6] = 22;
    lcm[3] = 13;lcm[7] = 23;lcm[10] = 33;
    lcm[4] = 14;lcm[8] = 24;lcm[11] = 34;lcm[13] = 44;
    lcm[5] = 15;lcm[9] = 25;lcm[12] = 35;lcm[14] = 45;lcm[15] = 55;
}
void insert(int i,int j)
{
    if(h[i])
    {
        r[num] = h[i];
        l[num] = l[h[i]];
        l[r[num]] = num;
        r[l[num]] = num;
    }
    else
        h[i] = l[num] = r[num] = num;
    s[j] ++;
    u[num] = u[j];
    d[num] = j;
    d[u[j]] = num;
    u[j] = num;
    col[num] = j;
    row[num] = i;
    num ++;
}
void remove(int x)
{
    int i,j;
    l[r[x]] = l[x];
    r[l[x]] = r[x];
    for(i = d[x];i != x;i = d[i])
        for(j = r[i];j != i;j = r[j])
        {
            u[d[j]] = u[j];
            d[u[j]] = d[j];
            s[col[j]] --;
        }
}
void resume(int x)
{
    int i,j;
    for(i = u[x];i != x;i = u[i])
        for(j = l[i];j != i;j = l[j])
        {
            s[col[j]] ++;
            u[d[j]] = d[u[j]] = j;
        }
    l[r[x]] = r[l[x]] = x;
}
void dfs(int k)
{
    if(ok)
        return;
    int i,j;
    if(!r[0])
    {
        ok = true;
        memset(aans,0,sizeof(aans));
        for(i = 0;i < k;i ++)
        {
            int ii = (ans[i] - 1)/15 + 1;
            int jj = ans[i] - (ii - 1) * 15;
            aans[ii][0] = lcm[jj]/10;
            aans[ii][1] = lcm[jj]%10;
        }
        for(i = 1;i <= n;i ++)
            printf("%d %d\n",aans[i][0],aans[i][1]);
        return;
    }
    int mx = M;
    int c;
    for(i = r[0];i;i = r[i])
    {
        if(s[i] < mx)
        {
            mx = s[i];
            c = i;
        }
    }
    remove(c);
    int tmp;
    for(i = d[c];i != c;i = d[i])
    {
        tmp = (row[i] - 1)/15 + 1;//判重
        if(vis[tmp] == true)
            continue;
        vis[tmp] = true;
        ans[k] = row[i];
        for(j = r[i];j != i;j = r[j])
            remove(col[j]);
        dfs(k + 1);
        if(ok)
            return;
        for(j = l[i];j != i;j = l[j])
            resume(col[j]);
        vis[tmp] = false;
    }
    resume(c);
}
int main()
{
    int a,b,i,j,ii,jj,st,ed;
    while(scanf("%d",&n) != EOF)
    {
        scanf("%d%d",&m,&D);
        init();
        while(m --)
        {
            scanf("%d%d",&a,&b);
            flag[a][b] = flag[b][a] = true;
        }
        for(i = 1;i <= n;i ++)//可以給自己供電
            flag[i][i] = true;
        for(i = 1;i <= n;i ++)//建圖
        {
            scanf("%d%d",&st,&ed);
            int base = (i - 1) * 15;
            for(ii = st;ii <= ed;ii ++)//可能的時間段
            {
                for(jj = st;jj <= ii;jj ++)
                {
                    for(j = 1;j <= n;j ++)//i可以供電的城市
                        if(flag[i][j] == true)
                        {
                            for(int ai = jj;ai <= ii;ai ++)
                                insert(base + idx[ii][jj],(j - 1) * D + ai);
                        }
                }
            }
        }
        ok = false;
        dfs(0);
        if(ok == false)
            puts("No solution");
        puts("");
    }
    return 0;
}


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