Woj 1550 - D - Jewelry

来源:互联网 发布:sci一区二区 知乎 编辑:程序博客网 时间:2024/06/05 16:28

题目


n*m的矩阵里有障碍,有珠宝(个数<=20),有空地,空地可以放灯,灯有四种可以照明方式,灯不能照到障碍,也不能照到矩阵以外的区域,求在照到所有珠宝的前提下,最少用多少灯。。


比赛时很多队伍过了,但我们还是不会做,赛后看了结题报告才会,听说还是个学弟出的题。哎,我弱爆了。

对于每盏灯合法的状态最多四种,我们需要从中选一种,这就是分组背包!预处理出,每盏灯的每种合法状态能照亮哪些珠宝。。

#include <stdio.h>#include <string.h>#include <algorithm>#include <map>#include <vector>using namespace std;int num[22][22];int cnt;int n,m;int f[(1<<21)];char s[22][22];vector<int>ok[20*20];int main(){    while(~scanf("%d%d",&n,&m)){        cnt=0;        memset(num,0,sizeof(num));        for(int i=0;i<n;i++){            for(int j=0;j<m;j++){                ok[i*n+j].clear();            }        }        for(int i=0;i<n;i++){            scanf("%s",s[i]);            for(int j=0;j<m;j++){                if(s[i][j]=='M'){                    num[i][j]=cnt;                    cnt++;                }            }        }        if(cnt==0){            puts("0");continue;        }        for(int i=0;i<n;i++){            for(int j=0;j<m;j++){                if(s[i][j]=='.'){                    //up_left                    int x=i-1,y=j-1;                    if(x>=0 && y>=0){                        int st=0;                        if(s[x][j]!='*' && s[i][y]!='*'){                            if(s[x][j]=='M') st |= 1<<(num[x][j]);                            if(s[i][y]=='M') st |= 1<<(num[i][y]);                            if(st!=0) ok[i*n+j].push_back(st);                        }                    }                    //up_right                    x=i-1,y=j+1;                    if(x>=0 && y<m){                        int st=0;                        if(s[x][j]!='*' && s[i][y]!='*'){                            if(s[x][j]=='M') st |= 1<<(num[x][j]);                            if(s[i][y]=='M') st |= 1<<(num[i][y]);                            if(st!=0) ok[i*n+j].push_back(st);                        }                    }                    //down_left                    x=i+1,y=j-1;                    if(x<n && y>=0){                        int st=0;                        if(s[x][j]!='*' && s[i][y]!='*'){                            if(s[x][j]=='M') st |= 1<<(num[x][j]);                            if(s[i][y]=='M') st |= 1<<(num[i][y]);                            if(st!=0) ok[i*n+j].push_back(st);                        }                    }                    //down_right                    x=i+1,y=j+1;                    if(x<n && y<m){                        int st=0;                        if(s[x][j]!='*' && s[i][y]!='*'){                            if(s[x][j]=='M') st |= 1<<(num[x][j]);                            if(s[i][y]=='M') st |= 1<<(num[i][y]);                            if(st!=0) ok[i*n+j].push_back(st);                        }                    }                }            }        }        int all=1<<(cnt);        for(int i=0;i<=all;i++) f[i]=4000;        f[0]=0;        for(int i=0;i<n;i++){            for(int j=0;j<m;j++){                if(s[i][j]=='.' && ok[i*n+j].size()>0){                    for(int k=all-1;k>=0;k--){                        for(int r=0;r<ok[i*n+j].size();r++){                            int st=ok[i*n+j][r];                            if((k&st) ==st ){                                f[k]=min(f[k],f[k&(~st)]+1);                            }                        }                    }                }            }        }        if(f[all-1]==4000) puts("-1");        else printf("%d\n",f[all-1]);    }    return 0;}


0 0