BZOJ2595: [Wc2008]游览计划

Description

Input

第一行有两个整数,N和 M,描述方块的数目。 
接下来 N行, 每行有 M 个非负整数, 如果该整数为 0, 则该方块为一个景点;
否则表示控制该方块至少需要的志愿者数目。 相邻的整数用 (若干个) 空格隔开,
行首行末也可能有多余的空格。

Output


由 N + 1行组成。第一行为一个整数,表示你所给出的方案
中安排的志愿者总数目。 
接下来 N行,每行M 个字符,描述方案中相应方块的情况: 
z  ‘_’(下划线)表示该方块没有安排志愿者; 
z  ‘o’(小写英文字母o)表示该方块安排了志愿者; 
z  ‘x’(小写英文字母x)表示该方块是一个景点; 
注:请注意输出格式要求,如果缺少某一行或者某一行的字符数目和要求不
一致(任何一行中,多余的空格都不允许出现) ,都可能导致该测试点不得分。

Sample Input

4 4
0 1 1 0
2 5 5 1
1 5 5 1
0 1 1 0

Sample Output

6
xoox
___o
___o
xoox

HINT

 对于100%的数据,N,M,K≤10,其中K为景点的数目。输入的所有整数均在[0,2^16]的范围内

求过给定点的最小生成树:斯坦纳树开搞

考虑DP,有两个DP:dp[i][j] 表示到达i这个点,当前状态为j ,注意第二维是状压,用来表示给定点是否被选

dp[ i ][ j ]=min{ dp[ i ][ j ],dp[ i ][ k ]+dp[ i ][ l ] }

dp[ i ][ j ]=min{ dp[ i ][ j ],dp[ i' ][ j ]+cost i to i'}这个用SPFA一起随DP跑

复杂度很高,O(n*3^k),慎用

代码如下:

//MT_LI
#include<cstdio> #include<cstring> #include<cstdlib> #include<algorithm> #include<cmath> #include<queue> #include<vector> #include<ctime> #include<map> #include<bitset> #include<set> #define ll long long #define mp(x,y) make_pair(x,y) #define pll pair<long long,long long> #define pii pair<int,int> using namespace std; inline int read() { int f=1,x=0;char ch=getchar(); while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();} while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();} return x*f; } int stack[20]; inline void write(int x) { if(x<0){putchar('-');x=-x;} if(!x){putchar('0');return;} int top=0; while(x)stack[++top]=x%10,x/=10; while(top)putchar(stack[top--]+'0'); } inline void pr1(int x){write(x);putchar(' ');} inline void pr2(int x){write(x);putchar('\n');} int n,m; struct node{ int x,y,next; }a[410];int len,last[110]; void ins(int x,int y){a[++len]=(node){x,y,last[x]};last[x]=len;} int head,tail,list[210];bool v[210]; int pre[110][2100]; int f[110][2100]; int c[110],cnt; int dx[4]={1,0,-1,0}; int dy[4]={0,1,0,-1}; void spfa(int u) { while(head!=tail) { int x=list[head]; for(int k=last[x];k;k=a[k].next) { int y=a[k].y; if(f[y][u]>f[x][u]+c[y]) { f[y][u]=f[x][u]+c[y]; pre[y][u]=-x; if(v[y]==false) { v[y]=true; list[tail++]=y; if(tail==200)tail=1; } } } head++;if(head==200)head=1; v[x]=false; } } char ss[110]; void dfs(int x,int u) { if(ss[x]!='x')ss[x]='o'; if(pre[x][u]>0) dfs(x,pre[x][u]),dfs(x,u^pre[x][u]); else if(pre[x][u]<0) dfs(-pre[x][u],u); } int main() { n=read(),m=read();cnt=0; len=0;memset(last,0,sizeof(last)); memset(f,63,sizeof(f)); for(int i=1;i<=n;i++) for(int j=1;j<=m;j++) { int pos=(i-1)*m+j; c[pos]=read(); if(c[pos]==0)cnt++,f[pos][1<<(cnt-1)]=0; for(int k=0;k<4;k++) { int edx=i+dx[k],edy=j+dy[k]; if(1<=edx&&edx<=n&&1<=edy&&edy<=m) ins(pos,(edx-1)*m+edy); } } head=1,tail=1; for(int u=1;u<=((1<<cnt)-1);u++) { for(int i=1;i<=n*m;i++) for(int v=((u-1)&u);v;v=((v-1)&u)) if(f[i][u]>f[i][v]+f[i][u^v]-c[i]) { f[i][u]=f[i][v]+f[i][u^v]-c[i]; pre[i][u]=v; } memset(v,false,sizeof(v)); for(int i=1;i<=n*m;i++) if(f[i][u]!=f[0][0]) { v[i]=true; list[tail++]=i; if(tail==200)tail=1; } spfa(u); } int ans=f[0][0],pos; for(int i=1;i<=n*m;i++) if(ans>f[i][(1<<cnt)-1])ans=f[i][(1<<cnt)-1],pos=i; for(int i=1;i<=n;i++) for(int j=1;j<=m;j++) if(c[(i-1)*m+j]==0)ss[(i-1)*m+j]='x'; else ss[(i-1)*m+j]='_'; dfs(pos,(1<<cnt)-1); printf("%d\n",ans); for(int i=1;i<=n;i++) { for(int j=1;j<=m;j++)printf("%c",ss[(i-1)*m+j]); printf("\n"); } return 0; }

 

posted @ 2019-03-24 17:14  MT_LI  阅读(167)  评论(0编辑  收藏  举报