Light Up
| Time Limit: 1000MS |
|
Memory Limit: 65536K |
| Total Submissions: 737 |
|
Accepted: 285 |
Description
Light Up is a puzzle set in a rectangular board divided in smaller squares. Some squares in the board are ``empty'' (white squares the figure below), some squares are ``barriers'' (dark squares in the figure below). A barrier square may have an integer number
i associated to it (0 <= i <= 4).
Figure 2: (a) Puzzle with 6 rows, 7 columns and 7 barriers; (b) a solution to the puzzle.
In this puzzle the goal is to ``light up'' all the empty squares by placing lamps in some of them (lamps are depicted as circles in the figure). Each lamp illuminates the square it is on, plus all squares in line with it, horizontally or vertically, up to a
barrier square or the board end.
A winning configuration satisfies the following conditions:
- all empty squares must be lit;
- no lamp may be lit by another lamp;
- all numbered barrier squares must have exactly that number of lamps adjacent to them (in the four squares above, below, and to the side);
- non-numbered barrier squares may have any number of lamps adjacent to them.
You must write a program to determine the smallest number of lamps that are needed to reach a winning configuration.
Input
The input contains several test cases. The first line of a test case contains two integers N, M indicating respectively the number of rows and the number of columns of the board (1 <= N <= 7, 1 <= M <= 7). The second line contains one integer B indicating the
number of barrier squares (0 <= B <= N × M). Each of the next B lines describe a barrier, containing three integers R, C and K, representing respectively the row number (1 <= R <= N), the column number (1 <= C <= M) and the barrier number (-1 <= K <= 4); K
= -1 means the barrier is unnumbered. The end of input is indicated by N = M = 0.
Output
For each test case in the input your program must produce one line of output, containing either an integer indicating the smallest number of lamps needed to reach a winning configuration, in case such a configuration exists, or the words `No solution'.
Sample Input
2 202 212 2 16 772 3 -13 3 04 2 15 4 35 6 21 7 -16 5 -10 0
Sample Output
2No solution8
題意:很簡單 不說了 如果要做這題 連題意都看不懂的話 就好好去學英語吧
思路:dfs+剪枝 地圖不大 將所有情況搜尋都搜一遍 最後判斷是否滿足條件 然後更新ans
不過這題剪枝還是必須的 具體代碼解釋的詳細 這裡不說了
#include <iostream>#include <cstdio>#include <cstring>#include <cmath>#define maxn 10using namespace std;int n,m,b,ans;int mp[maxn][maxn];int vis[maxn][maxn];int jmp[maxn][maxn];int light[maxn][maxn];int dx[]= {-1,1,0,0};int dy[]= {0,0,-1,1};void showvis() // 中間輸出 方便debug{ int i,j; printf("\n"); for(i=1; i<=n; i++) { for(j=1; j<=m; j++) { printf("%d",vis[i][j]); } printf("\n"); }}bool isok(int tx,int ty) // 判斷能否放燈{ int i,j; for(i=tx-1; i>=1; i--) { if(vis[i][ty]) return false; else if(mp[i][ty]) break ; } for(i=tx+1; i<=n; i++) { if(vis[i][ty]) return false; else if(mp[i][ty]) break ; } for(j=ty-1; j>=1; j--) { if(vis[tx][j]) return false; else if(mp[tx][j]) break ; } for(j=ty+1; j<=m; j++) { if(vis[tx][j]) return false; else if(mp[tx][j]) break ; } return true ;}void expand(int tx,int ty) // 擴充 將燈能照亮的地方都點亮{ int i,j; for(i=tx; i>=1; i--) { if(mp[i][ty]) break ; else jmp[i][ty]=1; } for(i=tx; i<=n; i++) { if(mp[i][ty]) break ; else jmp[i][ty]=1; } for(j=ty-1; j>=1; j--) { if(mp[tx][j]) break ; else jmp[tx][j]=1; } for(j=ty+1; j<=m; j++) { if(mp[tx][j]) break ; else jmp[tx][j]=1; }}bool judge() // 判斷搜出來的情況是否合理{ int i,j,k,cnt; memset(jmp,0,sizeof(jmp)); for(i=1; i<=n; i++) { for(j=1; j<=m; j++) { if(vis[i][j]) expand(i,j); // 將標記了的都擴充 } } for(i=1; i<=n; i++) { for(j=1; j<=m; j++) { if(!mp[i][j]&&!jmp[i][j]) return false ; // 如果還有一個位置沒亮的話就不行 } }// showvis(); for(i=1; i<=n; i++) // 檢測牆的周圍燈的個數是否滿足條件 { for(j=1; j<=m; j++) { if(light[i][j]==-1) continue ; cnt=0; for(k=0; k<4; k++) { if(vis[i+dx[k]][j+dy[k]]) cnt++; } if(cnt!=light[i][j]) return false ; } } return true ;}bool midcut(int tx,int ty) // 中間剪枝 如果有牆的周圍不滿足條件了 就 return false{ int i,j,k,cnt; for(i=1; i<=tx-2; i++) { for(j=1; j<=m; j++) { if(light[i][j]==-1) continue ; cnt=0; for(k=0; k<4; k++) { if(vis[i+dx[k]][j+dy[k]]) cnt++; } if(cnt!=light[i][j]) return false ; } } i=tx-1; for(j=1; j<=ty-1; j++) { if(light[i][j]==-1) continue ; cnt=0; for(k=0; k<4; k++) { if(vis[i+dx[k]][j+dy[k]]) cnt++; } if(cnt!=light[i][j]) return false ; } return true ;}bool goodcut(int tx,int ty) // 強剪枝 如果所搜點為牆 且其上方為黑暗的,則剪枝!{ int i,j,k,cnt; memset(jmp,0,sizeof(jmp)); for(i=1; i<=tx-1; i++) { for(j=1; j<=m; j++) { if(vis[i][j]) expand(i,j); } } if(!jmp[tx-1][ty]) return false; return true ;}void dfs(int nx,int ny,int cxx){ if(ans<=cxx) return ; if(!midcut(nx,ny)) return ; // 中間剪枝可以不要 其實在poj上不要還快一些 因為他的資料沒有偏重這一點 if(nx>=n&&ny>m||nx>n) { if(judge()) // 全部搜完後判斷情況是否合理 { if(ans>cxx) ans=cxx; // 更新ans } return ; } if(ny>m) dfs(nx+1,1,cxx); else if(mp[nx][ny]) { if(nx>=2&&!mp[nx-1][ny]&&!goodcut(nx,ny)) return ; // 注意前面的條件 dfs(nx,ny+1,cxx); } else { dfs(nx,ny+1,cxx); if(!vis[nx][ny]&&isok(nx,ny)) { vis[nx][ny]=1; dfs(nx,ny+1,cxx+1); vis[nx][ny]=0; } }}int main(){ int i,j,r,c,k; while(scanf("%d%d",&n,&m),n||m) { scanf("%d",&b); memset(mp,0,sizeof(mp)); memset(light,-1,sizeof(light)); for(i=1; i<=b; i++) { scanf("%d%d%d",&r,&c,&k); mp[r][c]=1; light[r][c]=k; } memset(vis,0,sizeof(vis)); ans=1000000; dfs(1,1,0); if(ans<1000000) printf("%d\n",ans); else printf("No solution\n"); } return 0;}/*ps:如果能夠過這組資料就不會TLE了7 7241 2 -11 4 -11 6 -12 1 -12 3 -12 5 -12 7 -13 2 -13 4 -13 6 -14 1 -14 3 -14 5 -14 7 -15 2 -15 4 -15 6 -16 1 -16 3 -16 5 -16 7 -17 2 -17 4 -17 6 -1ans: 25*/