【题解】P2566 [SCOI2009] 围豆豆
1:性质一
根据射线定理,发现一个豆豆被围住当且仅当向右引一条射线与轮廓交点为奇数
2:性质二
要求出合法回路的价值,我们需要统计这些合法回路 包含的物品 以及 路径长
3:性质三
一些 从相同起点到\((x,y)\) 且 包含的物品集合相同 的路径集合,它们是等价的
在这些等价路径中,我们只需要求它们的最小长度
4:操作
定义 \(val(S):S\) 集合价值和
枚举起点,跑 \(SPFA\) ,队列节点记录{位置,包含物品集合}
然后在 \(val(k)-dp[fx][fy][k]\) 中取最大值( \(fx,fy\) 为起点)
5:代码
#include<bits/stdc++.h>
#define Pair pair<int,int>
#define x first
#define y second
using namespace std;
const int N=11;
int nw[N];
int mp[N][N];
Pair line[N];
int vis[N][N][1<<N];
int dp[N][N][1<<N];
struct node{
int x,y,S;
};
int n,m;int d;
int fx[4][2]={{1,0},{-1,0},{0,1},{0,-1}};
int check(int x,int y,int dx,int dy,int S){
if(x==dx) return S;
for(int i=0;i<d;i++){
int mx=line[i].x,my=line[i].y;
if(((mx==x&&mx<dx)||(mx==dx&&mx<x))&&my<y) S^=1<<i;
}
return S;
}
int val[1<<N];
int solve(int ftx,int fty){
memset(dp,0x3f,sizeof dp);
queue<node> q;
q.push({ftx,fty,0});
vis[ftx][fty][0]=1;
dp[ftx][fty][0]=0;
while(q.size()){
node tmp=q.front();q.pop();
int x=tmp.x,y=tmp.y,S=tmp.S;
vis[x][y][S]=0;
for(int dur=0;dur<4;dur++){
int dx=x+fx[dur][0],dy=y+fx[dur][1];
if(!(1<=dx&&dx<=n&&1<=dy&&dy<=m)||mp[dx][dy]) continue;
int T=check(x,y,dx,dy,S);
if(dp[x][y][S]+1<dp[dx][dy][T]){
dp[dx][dy][T]=dp[x][y][S]+1;
if(!vis[dx][dy][T]) q.push({dx,dy,T});
}
}
}
int ans=0;
//if(ftx==3&&fty==2) cout<<dp[ftx][fty][3]<<"\n";
for(int S=0;S<(1<<d);S++){
ans=max(ans,val[S]-dp[ftx][fty][S]);
}
return ans;
}
int main(){
cin>>n>>m;
cin>>d;
for(int i=0;i<d;i++) cin>>nw[i];
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++){
char k;cin>>k;
if(k=='0') mp[i][j]=0;
else if(k=='#') mp[i][j]=-1;
else{
mp[i][j]=k-'0';
line[mp[i][j]-1]={i,j};
}
}
}
for(int S=0;S<(1<<d);S++){
for(int i=0;i<d;i++){
if(S>>i&1) val[S]+=nw[i];
}
}
int ans=0;
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++){
if(mp[i][j]==0) ans=max(ans,solve(i,j));
}
}
cout<<ans<<"\n";
return 0;
}
6:反思
轮廓包含节点可以考虑射线定理

浙公网安备 33010602011771号