BZOJ 2595 斯坦那树

Posted on 2016-05-27 11:00  yyjxx2010xyu  阅读(118)  评论(0编辑  收藏  举报

很久以前就想做,后来弃坑了。

最近又在群里有人问了类似的问题,艾老师说是斯坦纳树(%%%)

就是状压DP,然后用Spfa对状态进行转移.

  1  
  2 #include <iostream>
  3 #include <cstring>
  4 #include <cstdio>
  5 #include <algorithm>
  6 #include <queue>
  7 using namespace std;
  8 const int Maxn=15;
  9 const int Maxm=1030;
 10 const int Inf=0x3f3f3f3f;
 11 const int Px=102501;
 12 const int Py=1024;
 13 const int dx[]={0,0,1,-1};
 14 const int dy[]={1,-1,0,0};
 15 //==================================
 16 int n,m,K,Sta,g[Maxn][Maxn],f[Maxn][Maxn][Maxm],pre[Maxn][Maxn][Maxm],STA[Maxn][Maxn];
 17 bool used[1200130],Ans[Maxn][Maxn];
 18 queue<int> Q;
 19 inline int Calc(int x,int y,int s) {return x*Px+y*Py+s;}
 20 inline bool Check(int a,int b) {return (a|b)==a;}
 21 inline bool Judge(int x,int y) {return (x>=1 && x<=n) && (y>=1 && y<=m);}
 22 void Spfa(int sta)
 23 {
 24     while (!Q.empty())
 25     {
 26         int u=Q.front(); Q.pop();
 27         int x=u/Px,y=u%Px/Py;
 28         for (int d=0;d<4;d++)
 29         {
 30             int p=x+dx[d],q=y+dy[d];
 31             int r=sta|STA[p][q];
 32             if (!Judge(p,q)) continue;
 33             if (f[p][q][r]>f[x][y][sta]+g[p][q])
 34             {
 35                 f[p][q][r]=f[x][y][sta]+g[p][q];
 36                 pre[p][q][r]=u;
 37                 int k=Calc(p,q,r);
 38                 if (!used[k] && sta==r) used[k]=true,Q.push(k);
 39             }
 40         }
 41         used[u]=false;
 42     }
 43 }
 44  
 45 void Init(int x,int y,int sta)
 46 {
 47     Ans[x][y]=true;
 48     int k=pre[x][y][sta];
 49     if (!k) return;
 50     int i=k/Px,j=k%Px/Py,s=k%Px%Py;
 51     Init(i,j,s);
 52     if (i==x && j==y) Init(i,j,sta-s);
 53 }
 54  
 55 void Out()
 56 {
 57     for (int i=1;i<=n;i++)
 58     {
 59         for (int j=1;j<=m;j++)
 60             if (Ans[i][j])
 61                 if (g[i][j]) putchar('o'); else putchar('x');
 62              else putchar('_');
 63         putchar('\n');
 64     }
 65 }
 66         
 67      
 68 int main()
 69 {
 70     scanf("%d%d",&n,&m);
 71     for (int i=1;i<=n;i++)
 72         for (int j=1;j<=m;j++)
 73             for (int k=0;k<=(1<<10);k++) f[i][j][k]=Inf;
 74          
 75     for (int i=1;i<=n;i++)
 76         for (int j=1;j<=m;j++)
 77         {
 78             scanf("%d",&g[i][j]);
 79             if (!g[i][j]) STA[i][j]=(1<<(K++)),f[i][j][STA[i][j]]=0;
 80         }
 81     Sta=(1<<K);
 82     for (int sta=1;sta<Sta;sta++)
 83     {
 84         for (int i=1;i<=n;i++)
 85             for (int j=1;j<=m;j++)
 86             {
 87                 for (int s=1;s<sta;s++)
 88                     if (Check(sta,s))
 89                         if (f[i][j][sta]>f[i][j][s]+f[i][j][sta-s]-g[i][j])
 90                         f[i][j][sta]=f[i][j][s]+f[i][j][sta-s]-g[i][j],
 91                         pre[i][j][sta]=Calc(i,j,s);
 92                 if (f[i][j][sta]!=Inf)
 93                 Q.push(Calc(i,j,sta)),used[Calc(i,j,sta)]=true;
 94             }
 95         Spfa(sta);
 96     }
 97  
 98     for (int i=1;i<=n;i++)
 99         for (int j=1;j<=m;j++)
100             if (!g[i][j]) 
101             {
102                 printf("%d\n",f[i][j][Sta-1]);
103                 Init(i,j,Sta-1);
104                 Out();
105                 return 0;
106             }
107     return 0;
108 }
109     
C++