华师一附中OI组

 找回密码
 立即注册
搜索
热搜: 活动 交友 discuz
查看: 2017|回复: 2
打印 上一主题 下一主题

poj2870Light Up

[复制链接]

738

主题

1485

帖子

5422

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
5422
跳转到指定楼层
楼主
发表于 2018-5-13 00:12:02 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
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 2
0
2 2
1
2 2 1
6 7
7
2 3 -1
3 3 0
4 2 1
5 4 3
5 6 2
1 7 -1
6 5 -1
0 0
Sample Output

2
No solution
8
Source

South America 2005


题目大意:给一个地图,地图最大7*7,里面有空地,有障碍,障碍有标号,标号-1~4,-1表示该障碍附近能放任意灯泡,其他的障碍周围只能恰好放与障碍标号相同数量的灯泡。一个灯泡能点亮该行该列的所有空地(除去障碍物遮挡)。求最少的放置灯泡数能照亮地图上所有的空地。注意已经被点亮的地方不能放灯泡。
回复

使用道具 举报

738

主题

1485

帖子

5422

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
5422
沙发
 楼主| 发表于 2018-5-13 00:13:19 | 只看该作者
题目分析:搜索。。。因为地图太小了,直接爆搜+剪枝也可以过。一开始也准备这样写的,写完超长的代码,一跑样例只过了2个,调试也很没心情。索性重写。重写的时候想了下,既然要保证有编号的障碍周围放固定数目的灯泡,与其盲目搜索,还不如先满足那些有编号的障碍物。于是想出了迭代加深搜索,因为地图太小,总共也不超过49步。也没想出好的启发函数,只能用朴素的迭代加深搜索。首先将有编号的障碍物找出来,先对障碍物进行一次dfs,找出满足所有有编号的障碍物的要求的一个可行解,然后再进一步Dfs,将剩下的没有点亮的空地点亮。
一共用到了2个数组,flag[i][j]=2表示ij位置是障碍,flag[i][j] = 3表示ij位置是灯泡,flag[i][j]= 0表示ij位置什么也没有。cover[i][j]表示ij位置是否被点亮,0表示未点亮,>0表示被点亮,因为同一个地方可能被照射多次,所以被点亮的点ij直接执行cover[i][j] ++。
最后还是被discuss里的一组数据卡住了,后来想了想,所有迭代加深的起点都是0,所以导致一开始的搜索都是明显不合法的,应该剪掉,所以迭代的深度的初始值用h()求出来。具体做法比较猥琐,就是扫描一遍初始地图,如果发现某个空地周围都是障碍,那么这个点至少要一个灯,统计出所有这样的情况,作为迭代的初始深度,然后就秒过了。。。
回复 支持 反对

使用道具 举报

738

主题

1485

帖子

5422

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
5422
板凳
 楼主| 发表于 2018-5-13 00:13:41 | 只看该作者
  1. #include<cstdio>  
  2. #include<cstring>  
  3. #include<cctype>  
  4. #include<algorithm>  
  5. using namespace std;  
  6. const int N = 9;  
  7. bool ok;  
  8. int flag[N][N];  
  9. int cover[N][N];  
  10. int dx[] = {1,-1,0,0};  
  11. int dy[] = {0,0,1,-1};  
  12. int n,m,b,ans;  
  13. struct node  
  14. {  
  15.     int x,y,val;  
  16. }barrier[50];  
  17. int cmp(struct node a,struct node b)  
  18. {  
  19.     return a.val < b.val;  
  20. }  
  21. int nextint()  
  22. {  
  23.     int ret;  
  24.     char c;  
  25.     bool sig = false;  
  26.     while(isspace(c = getchar()))  
  27.         ;  
  28.     if(c == '-')  
  29.     {  
  30.         sig = true;  
  31.         c = getchar();  
  32.     }  
  33.     ret = c - '0';  
  34.     while((c = getchar()) >= '0' && c <= '9')  
  35.         ret = ret * 10 + c - '0';  
  36.     return sig?-ret:ret;  
  37. }  
  38.   
  39. bool jud(int x,int y)  
  40. {  
  41.     return !(x >= 1 && y >= 1 && x <= n && y <= m);  
  42. }  
  43.   
  44. int h()  
  45. {  
  46.     int i,j;  
  47.     int ret = 0;  
  48.     for(i = 1;i <= n;i ++)  
  49.     {  
  50.         for(j = 1;j <= m;j ++)  
  51.         {  
  52.             if(!cover[i][j] && flag[i][j] != 2)  
  53.             {  
  54.                 if((flag[i - 1][j] == 2 || jud(i - 1,j))  
  55.                    && (flag[i + 1][j] == 2 || jud(i + 1,j))  
  56.                    && (flag[i][j - 1] == 2 || jud(i,j - 1))  
  57.                     && (flag[i][j + 1] == 2 || jud(i,j + 1)))  
  58.                     ret ++;  
  59.             }  
  60.         }  
  61.     }  
  62.     return ret;  
  63. }  
  64.   
  65. int put(int x,int y)  
  66. {  
  67.     int ret = 1;  
  68.     int i,j;  
  69.     i = x - 1;  
  70.     j = y;  
  71.     while(i > 0 && flag[i][j] != 2)  
  72.     {  
  73.         cover[i][j] ++;  
  74.         if(cover[i][j] == 1)  
  75.             ret ++;  
  76.         i --;  
  77.     }  
  78.     i = x + 1;  
  79.     j = y;  
  80.     while(i <= n && flag[i][j] != 2)  
  81.     {  
  82.         cover[i][j] ++;  
  83.         if(cover[i][j] == 1)  
  84.             ret ++;  
  85.         i ++;  
  86.     }  
  87.     i = x;  
  88.     j = y - 1;  
  89.     while(j > 0 && flag[i][j] != 2)  
  90.     {  
  91.         cover[i][j] ++;  
  92.         if(cover[i][j] == 1)  
  93.             ret ++;  
  94.         j --;  
  95.     }  
  96.     j = y + 1;  
  97.     while(j <= m && flag[i][j] != 2)  
  98.     {  
  99.         cover[i][j] ++;  
  100.         if(cover[i][j] == 1)  
  101.             ret ++;  
  102.         j ++;  
  103.     }  
  104.     return ret;  
  105. }  
  106.   
  107. void deput(int x,int y)  
  108. {  
  109.     int ret = 1;  
  110.     int i,j;  
  111.     i = x - 1;  
  112.     j = y;  
  113.     while(i > 0 && flag[i][j] != 2)  
  114.     {  
  115.         cover[i][j] --;  
  116.         i --;  
  117.     }  
  118.     i = x + 1;  
  119.     while(i <= n && flag[i][j] != 2)  
  120.     {  
  121.         cover[i][j] --;  
  122.         i ++;  
  123.     }  
  124.     i = x;  
  125.     j = y - 1;  
  126.     while(j > 0 && flag[i][j] != 2)  
  127.     {  
  128.         cover[i][j] --;  
  129.         j --;  
  130.     }  
  131.     j = y + 1;  
  132.     while(j <= m && flag[i][j] != 2)  
  133.     {  
  134.         cover[i][j] --;  
  135.         j ++;  
  136.     }  
  137. }  
  138.   
  139.   
  140. int check()//0 irllegal 1 ok 2 right  
  141. {  
  142.     int i,j;  
  143.     int tmp;  
  144.     int ret = 2;  
  145.     for(i = 0;i < b;i ++)  
  146.     {  
  147.         if(barrier[i].val == -1)  
  148.             continue;  
  149.         tmp = 0;  
  150.         for(j = 0;j < 4;j ++)  
  151.         {  
  152.             int tx = barrier[i].x + dx[j];  
  153.             int ty = barrier[i].y + dy[j];  
  154.             if(tx < 1 || ty < 1 || tx > n || ty > m)  
  155.                 continue;  
  156.             if(flag[tx][ty] == 3)  
  157.                 tmp ++;  
  158.         }  
  159.         if(tmp > barrier[i].val)  
  160.             return 0;  
  161.         if(tmp != barrier[i].val)  
  162.             ret = 1;  
  163.     }  
  164.     return ret;  
  165. }  
  166.   
  167. void print()  
  168. {  
  169.     int i,j;  
  170.     for(i = 1;i <= n;i ++)  
  171.     {  
  172.         for(j = 1;j <= m;j ++)  
  173.             printf("%d ",flag[i][j]);  
  174.         putchar(10);  
  175.     }  
  176.     putchar(10);  
  177.     for(i = 1;i <= n;i ++)  
  178.     {  
  179.         for(j = 1;j <= m;j ++)  
  180.             printf("%d ",cover[i][j]);  
  181.         putchar(10);  
  182.     }  
  183. }  
  184.   
  185. void Dfs(int x,int y,int cnt,int ca)  
  186. {  
  187.     if(ca > ans)  
  188.         return;  
  189.     int i,j;  
  190.     if(ok)  
  191.         return;  
  192.     if(cnt == m * n - b)  
  193.     {  
  194.         ok = true;  
  195.         return;  
  196.     }  
  197.     for(i = x;i <= n;i ++)  
  198.     {  
  199.         for(j = 1;j <= m;j ++)  
  200.         {  
  201.             if(flag[i][j] == 0 && cover[i][j] == 0)  
  202.             {  
  203.                 flag[i][j] = 3;  
  204.                 if(check() != 2)  
  205.                 {  
  206.                     flag[i][j] = 0;  
  207.                     continue;  
  208.                 }  
  209.                 int tp = put(i,j);  
  210.                 Dfs(i,j,cnt + tp,ca + 1);  
  211.                 deput(i,j);  
  212.                 flag[i][j] = 0;  
  213.             }  
  214.         }  
  215.     }  
  216. }  
  217.   
  218. void dfs(int id,int cnt,int ca)  
  219. {  
  220.     if(ca > ans)  
  221.         return;  
  222.     if(ok)  
  223.         return;  
  224.     if(id == b)  
  225.     {  
  226.         if(check() == 2)//right  
  227.         {  
  228.             Dfs(1,1,cnt,ca);  
  229.         }  
  230.         return;  
  231.     }  
  232.     int i,j;  
  233.     for(i = j = 0;i < 4;i ++)  
  234.     {  
  235.         if(flag[barrier[id].x + dx[i]][barrier[id].y + dy[i]] == 3)  
  236.             j ++;  
  237.     }  
  238.     if(j > barrier[id].val)  
  239.         return;  
  240.     else  
  241.     {  
  242.         if(j == barrier[id].val)  
  243.             dfs(id + 1,cnt,ca);  
  244.         else  
  245.         {  
  246.             for(i = 0;i < 4;i ++)  
  247.             {  
  248.                 int tx = barrier[id].x + dx[i];  
  249.                 int ty = barrier[id].y + dy[i];  
  250.                 if(tx < 1 || ty < 1 || tx > n || ty > m)  
  251.                     continue;  
  252.                 if(flag[tx][ty] == 0 && cover[tx][ty] == 0)  
  253.                 {  
  254.                     flag[tx][ty] = 3;  
  255.                     if(check() == 0)  
  256.                     {  
  257.                         flag[tx][ty] = 0;  
  258.                         continue;  
  259.                     }  
  260.                     int tp = put(tx,ty);  
  261.                     dfs(id,cnt + tp,ca + 1);  
  262.                     deput(tx,ty);  
  263.                     flag[tx][ty] = 0;  
  264.                 }  
  265.             }  
  266.         }  
  267.     }  
  268. }  
  269.   
  270. int main()  
  271. {  
  272.     int i,j;  
  273.     while(n = nextint())  
  274.     {  
  275.         m = nextint();  
  276.         if(m + n == 0)  
  277.             break;  
  278.         b = nextint();  
  279.         memset(flag,0,sizeof(flag));  
  280.         memset(cover,0,sizeof(cover));  
  281.         for(i = 0;i < b;i ++)  
  282.         {  
  283.             barrier[i].x = nextint();  
  284.             barrier[i].y = nextint();  
  285.             barrier[i].val = nextint();  
  286.             flag[barrier[i].x][barrier[i].y] = 2;//  
  287.         }  
  288.         sort(barrier,barrier + b,cmp);  
  289.   
  290.         ok = false;  
  291.         for(i = 0;i < b;i ++)  
  292.             if(barrier[i].val > 0)  
  293.                 break;  
  294.         ans = h();  
  295.         //print();  
  296.         while(1)  
  297.         {  
  298.             if(ok || ans > m * n - b)  
  299.                 break;  
  300.             dfs(i,0,0);  
  301.             if(ok)  
  302.                 break;  
  303.             ans ++;  
  304.         }  
  305.         if(ok == false)  
  306.             printf("No solution\n");  
  307.         else  
  308.             printf("%d\n",ans);  
  309.     }  
  310.     return 0;  
  311. }  
  312. //168K  94MS  
  313. /*
  314. 2 2
  315. 4
  316. 1 1 -1
  317. 1 2 -1
  318. 2 1 -1
  319. 2 2 -1
  320. 2 2
  321. 0
  322. 2 2
  323. 1
  324. 2 2 1
  325. 6 7
  326. 7
  327. 2 3 -1
  328. 3 3 0
  329. 4 2 1
  330. 5 4 3
  331. 5 6 2
  332. 1 7 -1
  333. 6 5 -1
  334. 7 7
  335. 24
  336. 1 2 -1
  337. 1 4 -1
  338. 1 6 -1
  339. 2 1 -1
  340. 2 3 -1
  341. 2 5 -1
  342. 2 7 -1
  343. 3 2 -1
  344. 3 4 -1
  345. 3 6 -1
  346. 4 1 -1
  347. 4 3 -1
  348. 4 5 -1
  349. 4 7 -1
  350. 5 2 -1
  351. 5 4 -1
  352. 5 6 -1
  353. 6 1 -1
  354. 6 3 -1
  355. 6 5 -1
  356. 6 7 -1
  357. 7 2 -1
  358. 7 4 -1
  359. 7 6 -1

  360. */  
复制代码
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

QQ|Archiver|手机版|小黑屋|服务支持:DZ动力|华师一附中OI组  

GMT+8, 2024-12-26 14:53 , Processed in 0.837681 second(s), 22 queries .

Powered by Discuz! X3.2

© 2001-2013 Comsenz Inc.

快速回复 返回顶部 返回列表