P1283 平板塗色

2021-09-07 14:42:43 字數 4686 閱讀 8851

ce數碼公司開發了一種名為自動塗色機(apm)的產品。它能用預定的顏色給一塊由不同尺寸且互不覆蓋的矩形構成的平板塗色。

為了塗色,apm需要使用一組刷子。每個刷子塗一種不同的顏色c。apm拿起一把有顏色c的刷子,並給所有顏色為c且符合下面限制的矩形塗色:

為了避免顏料滲漏使顏色混合,乙個矩形只能在所有緊靠它上方的矩形塗色後,才能塗色。例如圖中矩形f必須在c和d塗色後才能塗色。注意,每乙個矩形必須立刻塗滿,不能只塗一部分。

寫乙個程式求乙個使apm拿起刷子次數最少的塗色方案。注意,如果一把刷子被拿起超過一次,則每一次都必須記入總數中。

輸入格式:

第一行為矩形的個數n。下面有n行描述了n個矩形。每個矩形有5個整數描述,左上角的y座標和x座標,右下角的y座標和x座標,以及預定顏色。

顏色號為1到20的整數。

平板的左上角座標總是(0, 0)。

座標的範圍是0..99。

n小於16。

輸出格式:

輸出至檔案paint.out,檔案中記錄拿起刷子的最少次數。

輸入樣例#1:

7

0 0 2 2 1

0 2 1 6 2

2 0 4 2 1

1 2 4 4 2

1 4 3 6 1

4 0 6 4 1

3 4 6 6 2

輸出樣例#1:

3
來自洛谷題解

1、一看到n<=16,顏色<=20,馬上就要想到裸的狀壓dp,

設dp[s][i]表示在集合s(已經塗的矩形的集合)中,最後塗色的顏色是i,所需的最少拿刷子的次數。至於集合,就是用二進位制表示。

先預處理出每個矩形上面有哪些矩形,這個由於資料範圍比較小,都不用離散化,直接開個二維陣列弄個矩形覆蓋就行了。

至於具體的dp,應該還算是比較好寫的。

列舉一下最後一次塗的是第j個矩形,而第j個矩形的顏色是col[j],當然,這個第j個矩形必須滿足兩個限制:

1.j屬於s

2.j上面的矩形都屬於s

那麼dp(s,col[j])=min(dp(s-(1<

dp(s,col[j])=min(dp(s-(1<

這個還是很好理解的。

1 #include2 #include3 #include4

using

namespace

std;

5 templatevoid chkmin(t &a,t b)

6const

int inf=0x3f3f3f3f;7

const

int n=101;8

const

int m=21;9

intlx[m],size[m],ly[m],col[m],rx[m],ry[m];

10int n,a[n][n],dp[1

<<16+1

][m],up[m][m];

11 inline bool

in(int i,int

s)14 inline bool ok(int i,int

s)19

intmain()

27for (int i=1;i<=n;i++)

34 memset(dp,0x3f,sizeof

(dp));

35for (int i=1;i<=20;i++)

36 dp[0][i]=1;37

for (int i=1;i

45int ans=inf;

46for (int i=1;i<=20;i++)

47 chkmin(ans,dp[(1

<1

][i]);

48 printf("%d"

,ans);

49return0;

50 }

2、

看到資料範圍: n < 16 ?直接搜尋,但是應該要剪枝

讀入資料,統計顏色,然後每個顏色都試一遍,即把該顏色的且能塗的磚塗上。

下一次塗色不能塗上次塗過的色。塗完了記錄結果

為了不超時,加了兩個剪枝

至於判斷該磚是否能塗,先預處理,把緊鄰該磚上方的磚用陣列記錄下來,再判斷那些磚是否被塗

**如下(格式醜勿噴)

1 #include2 #include3 #include4 #include5 #include6 #include7

using

namespace

std;

8struct lbq //

結構體 a1b1 該磚左上角座標 a2b2 右下角座標 x 顏色

9a[20

];12

intccmp(lbq a,lbq b)

1317

bool d=false;18

int de[20]=;//

de陣列表示是否有該顏色

19int n,m,ans=999,b[20],fk[20][20]; //

b陣列代表該磚是否被塗 fk[i][j]表示第i個磚是否緊鄰上方第j個磚 m 最大顏色編號

20bool ok(int

o)21

26void dfs(int o,int pq,int xx) //

o 塗色次數 pq 塗過顏色的磚 xx 上次塗的顏色

2734

for(int i=1;i<=m;i++) //

列舉顏色

3546

else

if(b[j]&&a[j].x==i) b[j]++;47}

48if(qq>0) dfs(o+1,pq+qq,i); 如果塗了磚,進行下一步

49for(int j=n;j>=1;j--) //

回溯一步

5056

else

if(b[j]>1&&a[j].x==i) b[j]--; 57}

58}59}

60}61int

main()

6271

for(int i=1;i<=20;i++) if(de[i]) m=i; //

求最大顏色編號

72 sort(a+1,a+n+1,ccmp); //

按左上角座標大小從小到大排序(先考慮縱,再考慮橫)

73for(int i=2;i<=n;i++)

74for(int j=i-1;j>=1;j--)

75if(a[i].a1==a[j].a2+1&& ( (a[i].b1>=a[j].b1&&a[i].b1<=a[j].b2) || (a[i].b2>=a[j].b1&&a[i].b2<=a[j].b2) ) )

76 fk[i][j]=1; //

如果i磚的最上面緊鄰j磚最下面,且兩磚橫座標有重疊部分,即j磚為i磚緊鄰上面的磚

77 dfs(0,0,0

);78 cout/

結果79

return0;

80 }

3、

用二進位制壓縮狀態,乙個n位二進位制數的第i位為0或1表示第i塊板是否圖上了色。

f[a][i]表示達到a狀態,最後一次塗色的顏色是i的最少換顏色次數。

檢查二進位制數a第i位是否為0: a&(1<

二進位制數a的第i位上的1變為0後的數: a-(1<

詳見**:

1 #include2

using

namespace

std;

3#define file(x) freopen(#x".in","r",stdin),freopen(#x".out","w",stdout)

4int f[(1

<<16)+1][21],n,color[20],b[100][100],maxcolor=0;5

int num[20],temp[20][20],xx[20],xy[20],yx[20],yy[20],ans=int_max;

6bool check(int a,int x)//

檢查a狀態下第x個矩形上方的所有矩形是否已經塗完色713

intmain()

1426

for(int i=1;i<=n;i++)

2738}39

for(int i=1;i<=maxcolor;i++)

40 f[0][i]=1;//

初始化,所有平板未塗色時需要拿一次刷子。

41for(int a=1;a<=((1

<1);a++)//

列舉每個著色狀態,n塊平板的狀態用二進位制表示就是0到(2^n-1),位運算優化

42for(int i=1;i<=n;i++)//

列舉放第i塊平板

43if(((1

<

<

檢查該狀態中是否已經塗上了第i個矩形,還有該狀態下第i個矩形的上方矩形是否都已塗完

44 51

for(int i=1;i<=maxcolor;i++)

52 ans=min(ans,f[(1

<1][i]);//

列舉最後顏色不同的最終狀態,取最小值為結果

53 printf("

%d\n

",ans);

54return0;

55 }

P1283 平板塗色

p1283 平板塗色 dfs 記憶化搜尋 將矩陣轉化為圖求解,然後我們發現這是個dag,於是就可以愉快地跑搜尋了。進行dfs時,我們可以用類似拓撲排序的方法。每次將上面所有矩形都被刷過 入度in i 0 的滿足條件的矩形用h陣列打個標記 用incol陣列表示目前h陣列中有幾種顏色,然後列舉可轉移狀態...

題解 P1283 平板塗色

ce 數碼公司開發了一種名為自動塗色機 apm 的產品。它能用預定的顏色給一塊由不同尺寸且互不覆蓋的矩形構成的平板塗色。為了塗色,apm 需要使用一組刷子。每個刷子塗一種不同的顏色 c ic i ci apm 拿起一把有顏色 c ic i ci 的刷子,並給所有顏色為 c ic i ci 且符合下面...

洛谷P1283 平板塗色(dfs)

ce數碼公司開發了一種名為自動塗色機 apm 的產品。它能用預定的顏色給一塊由不同尺寸且互不覆蓋的矩形構成的平板塗色。為了塗色,apm需要使用一組刷子。每個刷子塗一種不同的顏色c。apm拿起一把有顏色c的刷子,並給所有顏色為c且符合下面限制的矩形塗色 為了避免顏料滲漏使顏色混合,乙個矩形只能在所有緊...