Description
在 n 行 m 列的网格中,你要圈一些地。
你从左上角出发,最后返回左上角,路径内部的区域视为被你圈住。 你不可以进入网格内部, 只能在边上行走。 你的路径不能在左上角以外自交, 但是边足够宽, 你可以重复经过而不自交。
网格中有一些格子对你很重要,你要尽量圈住它;而另一些格子对你有坏处,你不能圈住它。
求圈住 i 个重要的格子的最小路径长度。
Solution
一开始看重要格子这么少以为是搜索然后最小割什么的
一个重要思想就是从点往上下左右四个方向做射线,如果与图形的交点数量是奇数说明在图形内
在这题里我们可以用10位二进制状态s记录每个重要点上方交点情况的奇偶性,用dis[x][y][s]表示走到(x,y)状态为s的最短路,然后统计dis[0][0]即可
Code
#include <stdio.h>
#include <string.h>
#include <algorithm>
#include <queue>
#define rep(i,st,ed) for (int i=st;i<=ed;++i)
#define fill(x,t) memset(x,t,sizeof(x))
#define fi first
#define se second
typedef std:: pair <int,int> pair;
typedef std:: pair <int,pair> bair;
const int INF=0x7fffffff;
std:: queue <bair> que;
std:: vector <pair> vec;
pair p[50005],dir[4]={pair(-1,0),pair(1,0),pair(0,-1),pair(0,1)};
int dis[52][52][2049],size;
int rc[52][52],ans[235],n,m;
bool vis[52][52][2049];
char str[52];
int get_S(int x,int y,int s,int k) {
int ret=s;
for (int ti=0;ti<size;ti++) {
pair i=vec[ti];
if (i.se==y&&k==3&&i.fi>x||i.se==y+1&&k==2&&i.fi>x) {
ret^=(1<<ti);
}
}
return ret;
}
void bfs() {
fill(dis,63);
dis[0][0][0]=0; vis[0][0][0]=1;
que.push(bair(0,pair(0,0)));
int x,y,s,S;
for (;!que.empty();) {
bair front=que.front(); que.pop();
x=front.fi; y=front.se.fi;
s=front.se.se;
pair now(x,y);
rep(k,0,3) {
pair tar=pair(now.fi+dir[k].fi,now.se+dir[k].se);
S=s; if (k>1) S=get_S(tar.fi,tar.se,s,k);
if (tar.fi>=0&&tar.fi<=n&&tar.se>=0&&tar.se<=m) {
if (dis[x][y][s]+1<dis[tar.fi][tar.se][S]) {
dis[tar.fi][tar.se][S]=dis[x][y][s]+1;
if (!vis[tar.fi][tar.se][S]) {
vis[tar.fi][tar.se][S]=1;
que.push(bair(tar.fi,pair(tar.se,S)));
}
}
}
}
vis[x][y][s]=0;
}
}
int main(void) {
freopen("data.in","r",stdin);
while (~scanf("%s",str+1)) {
n++; m=strlen(str+1);
rep(i,1,m) {
if (str[i]=='X') rc[n][i]=1;
else if (str[i]=='I') rc[n][i]=2;
if (str[i]!='.') vec.push_back(pair(n,i));
}
} size=vec.size();
bfs(); int mx=0;
fill(ans,63);
rep(s,1,-1+(1<<size)) {
int cnt=0;
for (int tj=0;tj<size;tj++) {
pair j=vec[tj];
if ((1<<tj)&s) {
if (rc[j.fi][j.se]==2) cnt++;
else {cnt=-1; break;}
}
}
if (cnt==-1) continue;
ans[cnt]=std:: min(dis[0][0][s],ans[cnt]);
mx=std:: max(mx,cnt);
}
rep(i,1,mx) printf("%d\n", ans[i]);
return 0;
}