bzoj2595 [Wc2008]游览计划
原题地址:http://www.lydsy.com/JudgeOnline/problem.php?id=2595
题意:
数据范围
N,M,K≤10,其中K为景点的数目。输入的所有整数均在[0,2^16]的范围内
题解:
dp[i][j][s]表景点联通状态为s,以(i,j)为根的最小代价。
两种转移:
dp[i][j][s]=dp[i][j][s’]+dp[i][j][s^s’]-a[i][j](合并子集,实际上是让树分叉)
dp[i][j][s]=dp[u][v][s’]+a[i][j] (向相邻点转移,因为转移有环,跑spfa)
一层一层地来就好。
感觉和Noip2017Day2T2挺像。
代码:
#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstring>
#include<queue>
using namespace std;
const int N=15;
const int inf=0x3f3f3f3f;
struct node
{
int x,y,s;
node(int x,int y,int s):x(x),y(y),s(s){}
};
queue<node> Q;
int n,m,po[N],a[N][N],cnt=0,dp[N][N][1500],top,pre[N][N][1500][3],fx[4]={0,-1,0,1},fy[4]={1,0,-1,0},num[N][N];
bool vis[N][N];
void dfs(int x,int y,int s)
{
vis[x][y]=1; if(!s) return;
dfs(pre[x][y][s][0],pre[x][y][s][1],pre[x][y][s][2]);
if(x==pre[x][y][s][0]&&y==pre[x][y][s][1]) dfs(pre[x][y][s][0],pre[x][y][s][1],s^pre[x][y][s][2]);
}
void cal(int x,int y)
{
printf("%d\n",dp[x][y][top-1]);
dfs(x,y,top-1);
for(int i=1;i<=n;i++)
{
for(int j=1;j<=m;j++)
{
if(!a[i][j]) printf("x");
else if(vis[i][j]) printf("o");
else printf("_");
}
printf("\n");
}
}
int main()
{
for(int i=0;i<=10;i++) po[i]=1<<i;
memset(dp,0x3f,sizeof(dp));
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)
{
scanf("%d",&a[i][j]);
if(!a[i][j]) {dp[i][j][po[cnt]]=0; num[i][j]=cnt; cnt++;}
}
top=1<<cnt;
for(int s=1;s<top;s++)
{
memset(vis,0,sizeof(vis));
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)
{
for(int ss=(s-1)&s;ss;ss=(ss-1)&s)
{
int kk=s^ss;
if(dp[i][j][ss]+dp[i][j][kk]-a[i][j]<dp[i][j][s])
{
dp[i][j][s]=dp[i][j][ss]+dp[i][j][kk]-a[i][j];
pre[i][j][s][0]=i; pre[i][j][s][1]=j; pre[i][j][s][2]=ss;
}
}
if(dp[i][j][s]<inf) {Q.push(node(i,j,s)); vis[i][j]=1;}
}
while(!Q.empty())
{
node u=Q.front(); Q.pop();
int x=u.x; int y=u.y; int s=u.s; vis[x][y]=0;
for(int d=0;d<4;d++)
{
int u=x+fx[d]; int v=y+fy[d];
if(u>0&&u<=n&&v>0&&v<=m)
{
int ss=a[u][v]?0:po[num[u][v]]; int ns=ss|s;
if(dp[x][y][s]+a[u][v]<dp[u][v][ns])
{
dp[u][v][ns]=dp[x][y][s]+a[u][v];
pre[u][v][ns][0]=x; pre[u][v][ns][1]=y; pre[u][v][ns][2]=s;
if(ns==s&&!vis[u][v]) {vis[u][v]=1; Q.push(node(u,v,s));}
}
}
}
}
}
memset(vis,0,sizeof(vis));
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)
if(a[i][j]==0) {cal(i,j); return 0;}
return 0;
}